1.1.14.7.15. fejezet, Hibajelenségek

Java annotációk

@Autowired és @Repository

Hibajelenség:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [hu.kepeslap.back.dao.ImageDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}

Az @Autowired annotáció használatakor (mondjuk egy konstruktornál) ügyeljünk arra, hogy a paraméterül átadott interfészt megvalósító osztályt (pl.: valamelyik DAOImpl osztály) jelöljük meg a @Repository annotációval.

@SessionScoped vs. @Scope("session")

A kettőt ne keverjük, mert a távoli GET kérésekkor meglepődhetünk, hogy több szál is elkezd dolgozni a kérésen, és egyáltalán nincs szinkronizáció a szálak közt. Ez több adatbázis műveletet elronthat, hiába használunk tranzakció kezelést. ManagedBean esetén ajánlott a @SessionScoped használata, Spring használatakor pedig a @Scope("session"). @Repostitory annotációnál is ajánlott a Scope("session") használata. Figyeljük meg, hogy a @Component annotációs objektumokat nem hozza létre automatikusan egy XHTML fájlban elhelyezett hivatkozás, ezért ezeket @Autowired annotációval egy @Controll osztályba érdemes beemelni.

Perzisztencia kivétel detached objektum

org.hibernate.PersistentObjectException: detached entity passed to persist

Használd a merge funkciót.

Tomcat

Connection Timeout

A telepített Tomcat config/server.xml-ben állítható mind a szinkron, mind az aszinkron időkorlát:

<Connector port="8080" protocol="HTTP/1.1" 
               minProcessors="3"
               maxProcessors="8"
               maxThreads="20"
               connectionTimeout="150000" 
               asyncTimeout="90000" />

(150 másodperc és 90 másodperc)

Quartz Servlet inicializálása

"cvc-complex-type.2.4.a: Invalid content was found starting with element 'init-param'"

A web.xml-ben a load-on-startup az init-param előtt volt. Helyesen:

<servlet>
    <servlet-name>QuartzInitializer</servlet-name>
    <servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
 
    <init-param>
      <param-name>shutdown-on-unload</param-name>
      <param-value>true</param-value>
    </init-param>
 
    <init-param>
      <param-name>start-scheduler-on-load</param-name>
      <param-value>false</param-value>
    </init-param>
 
    <load-on-startup>1</load-on-startup>
  </servlet>

Quartz XMLSchedulingDataProcessorPlugin

Hibajelenség:

21:34:52,052 ERROR [org.quartz.core.ErrorLogger] (MyScheduler_QuartzSchedulerThread) An error occurred while scanning for the next triggers to fire.: org.quartz.JobPersistenceException: Couldn't acquire next trigger: Lock wait timeout exceeded; try restarting transaction [See nested exception: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction]
	at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTrigger(JobStoreSupport.java:2827)
	at org.quartz.impl.jdbcjobstore.JobStoreSupport$41.execute(JobStoreSupport.java:2755)
	at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3798)
	at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTriggers(JobStoreSupport.java:2751)
	at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:264)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

Megoldás

org.quartz.plugin.jobInitializer.wrapInUserTransaction = true

quartz.properties

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.nonManagedTXDataSource = myNonTxDS
org.quartz.dataSource.myDS.jndiURL = java\:jboss/datasources/KepeslapR2DS
org.quartz.dataSource.myNonTxDS.jndiURL = java\:jboss/datasources/KepeslapR2NonTxDS
org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml 
org.quartz.plugin.jobInitializer.wrapInUserTransaction = true
org.quartz.dataSource.myDS.maxConnections = 30

quartz-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<job-scheduling-data
	xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData 
	http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd"
	version="1.8">
 
	<schedule>
		<job>
			<name>NOT-TIMED-JOB</name>
			<group>SERVER-SCAN-INTERVALL</group>
			<description>Send timeless mails</description>
			<job-class>hu.integrity.kepeslap.back.mail.DefaultMailDeliveryJob</job-class>
			<durability>true</durability>
			<recover>false</recover>
		</job>
		<trigger>
			<cron>
				<name>NOT-TIMED-TRIGGER</name>
				<group>SERVER-SCAN-INTERVALL</group>
				<job-name>NOT-TIMED-JOB</job-name>
				<job-group>SERVER-SCAN-INTERVALL</job-group>
				<!-- It will run every 5 seconds -->
				<cron-expression>0/20 * * * * ?</cron-expression>
			</cron>
		</trigger>
	</schedule>
</job-scheduling-data>

homework-ds.xml

<?xml version="1.0" encoding="UTF-8"?>
<datasources xmlns="http://www.jboss.org/ironjacamar/schema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.jboss.org/ironjacamar/schema http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd">
    <!-- The datasource is bound into JNDI at this location. We reference 
        this in META-INF/persistence.xml -->
    <datasource jndi-name="java:jboss/datasources/KepeslapR2DS"
        pool-name="KepeslapR2" enabled="true"
        use-java-context="true">
        <connection-url>jdbc:mysql://localhost:3306/kepeslap_jboss?useUnicode=true&amp;autoReconnect=true&amp;characterEncoding=UTF-8</connection-url>
        <driver>com.mysql</driver>
        <security>
            <user-name>admin</user-name>
            <password>pwd</password>
        </security>
    </datasource>    
    <!-- Datasource for Quartz non CMT transactions -->
    <datasource jndi-name="java:jboss/datasources/KepeslapR2NonTxDS"
        pool-name="KepeslapR2NonTx" enabled="true" jta="false"
        use-java-context="true">                
        <connection-url>jdbc:mysql://localhost:3306/kepeslap_jboss?useUnicode=true&amp;autoReconnect=true&amp;characterEncoding=UTF-8</connection-url>        
        <driver>com.mysql</driver>
        <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
        <security>
            <user-name>admin</user-name>
            <password>pwd</password>
        </security>                
    </datasource>
</datasources>

persistance.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
	xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
	<persistence-unit name="primary">
		<!-- If you are running in a production environment, add a managed data 
			source, this example data source is just for development and testing! -->
		<!-- The datasource is deployed as WEB-INF/KepeslapR2-ds.xml, you can find 
			it in the source at src/main/webapp/WEB-INF/KepeslapR2-ds.xml -->
		<jta-data-source>java:jboss/datasources/KepeslapR2DS</jta-data-source>
		<non-jta-data-source>java:jboss/datasources/KepeslapR2NonTxDS</non-jta-data-source>
		<properties>
			<!-- Properties for Hibernate -->			
			<property name="hibernate.hbm2ddl.auto" value="update" />
			<property name="hibernate.show_sql" value="false" />
		</properties>
	</persistence-unit>
</persistence>