Spring Learning Note (22) declarative transaction configuration, readonly Invalid write no exception

Source: Internet
Author: User
Tags one more line

In the previous section, we used a programmatic approach to configuring transactions, and the advantage is that we have a strong control over each method, such as what transactions I need to use, and where the exception needs to be rolled back, for a very fine-grained configuration. But in actual development, we may not need such a fine-grained configuration. On the other hand, if our project is large and the service layer method is many, it is tedious to configure the transaction separately for each method. And it can also cause a lot of duplication of code jumbled accumulation. In the face of these shortcomings, the first thing we think about is our spring AOP. The implementation of spring declarative transactions is based on AOP.
In this article, we describe spring's declarative transactional configuration.

Example analysis

The declarative transaction configuration principle is equivalent to using surround enhancement, intercepting the target method, weaving into our transaction before its invocation, and then committing or rolling back the transaction based on execution at the end of the call. The crosscutting logic allows our service layer to focus more on the processing of its own business logic without cumbersome transaction configuration.
The core of configuring declarative transactions is to configure our Transactionproxyfactorybean and Beannameautoproxycreator. Let's look at one of the following instance configurations

Transaction Core class Configuration
<bean id= "transactioninterceptor"class=" Org.springframework.transaction.interceptor.TransactionInterceptor ">            < property name="TransactionManager" ref="TransactionManager" /><!--Specify a transaction manager --    < property name="Transactionattributes"><!--Configure transaction Properties ' --        <props>            <prop key="add*" >Propagation_required,-exception</prop>             <prop key="update*">Propagation_required,+exception</prop>                 <prop key="delete*">Propagation_required</prop>            <prop key="*">Propagation_required</prop>        </props>    </Property ></Bean><Bean class="Org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >    < property name="Beannames"><!--configuration requires proxy bean-->        <list>            <value>Mybaseserviceimpl</value>        </list>    </Property >    < property name="Interceptornames"><!--declaring interceptors --        <list>            <value>Transactioninterceptor</value>        </list>    </Property ></Bean><!--the relevant dependencies for testing<bean id="Mybasedao" class="Com.yc.dao.MyBaseDaoImpl">     < property name="Sessionfactory" ref="Sessionfactory" / ></Bean><bean id= "Mybaseserviceimpl" class=" Com.yc.service.MyBaseServiceImpl ">    < property name="Mybasedao" ref="Mybasedao" /></Bean>
Attribute detailed analysis

In the instance we configure the interceptor and the proxy generator. When configuring the Transactioninterceptor transaction property, the key corresponds to the method name, and we match all the methods in the target class with the start of add, and we intercept the configuration transaction against the method of the target object class in the order that we block it according to the definition of the property, if it is key="add*"The transaction property is intercepted, even if there is a key="*"可以匹配任意方法,也不会再次被拦截。 transaction attribute format in the following tag:
传播行为 [,隔离级别] [,只读属性] [,超时属性] [,-Exception] [,+Exception]
In addition to the propagation behavior, the others are optional. Each property description is visible in the following table

The
Properties Description
propagation behavior value must begin with "Propagation_", including: Propagation_mandatory, propagation_nested, Propagation_ Never, propagation_not_supported, propagation_required, Propagation_requires_new, Propagation_supports, a total of seven kinds of values.
Isolation level values must begin with "Isolation_", including: Isolation_default, isolation_read_committed, Isolation_r ead_uncommitted, Isolation_repeatable_read, isolation_serializable, a total of five kinds of values.
Read-only property if the transaction is read-only, then we can specify a read-only property, specified with "ReadOnly". Otherwise we do not need to set this property. The
Time-out property values must begin with "Timeout_", followed by a value of type int, indicating the time-out, in seconds.
+exception The transaction still commits normally even if these types of exceptions are thrown in the transaction. You must precede each exception's name with a "+". The name of the exception can be part of the class name. such as "+runtimeexception", "+tion" and so on. You can specify more than one, such as +exception1,+exception2
-exception When these types of exceptions are thrown in a transaction, the transaction is rolled back. A "-" must precede each exception's name. The name of the exception can be all or part of the class name, such as "-runtimeexception", "-tion", and so on. You can specify more than one, such as-exception1,-exception2

As you can see from the configuration file, we can configure multiple interceptors and multiple beans to fit different transactions. This declarative transaction is convenient to use.

Service Layer Configuration

With declarative transactions, our service layer needs to be rewritten relative to the previous article example:

 Public  class Mybaseserviceimpl implements mybaseservice{    PrivateMybasedao Mybasedao;@Override     Public void Queryupdateuser(FinalInteger ID,FinalString newName) {User user = Mybasedao.queryunique (user.class, id);            SYSTEM.OUT.PRINTLN (user);            User.setname (NewName);            Mybasedao.update (user);    SYSTEM.OUT.PRINTLN (user); } Public void Setmybasedao(Mybasedao Mybasedao) { This. Mybasedao = Mybasedao; }}

As we can see, we have removed the intrusive injection of the transaction template and also removed the intrusive configuration of the transaction (in each method). Of course, the benefit of programmatic transactions is the ability to fine-grained transactions into each method. When the transactions of most of our methods are consistent, we can use declarative transactions for those that need to be configured independently, and we can exclude them from declarative transactions and then configure them separately using programmatic transactions or annotated transactions that we will refer to later.

Test results and analysis

Below, run our same test method:

publicclass Test1 {    @Test    publicvoidtest(){        new ClassPathXmlApplicationContext("classpath:spring/spring-datasource.xml");        MyBaseServiceImpl myBaseService= (MyBaseServiceImpl) ac.getBean("myBaseServiceImpl");        myBaseService.queryUpdateUser(1"newName2");    }}

Run the test method and you will find an error:

Java.lang.ClassCastException:com.sun.proxy. $ Proxy8 cannot is cast to Com.yc.service.MyBaseServiceImpl
This means that our proxy class cannot be converted to our custom service implementation class. The reason for this is because our beannameautoproxycreator does not use the Cglib proxy by default, so our proxy class is created using the JDK Dynamic agent based interface instead of class-based creation , we have the following two workarounds:
1. Convert the proxy class to an interface implemented by Mybaseserviceimpl Mybaseservice rather than Mybaseserviceimpl:
MyBaseService myBaseService= (MyBaseService) ac.getBean("myBaseServiceImpl");
2. Under Beannameautoproxycreator configuration, add:
<property name="proxyTargetClass" value="true"/>, i.e.

<Bean class="Org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >    < property name="Proxytargetclass" value="true"/>    < property name="Beannames">        <list>            <value>Mybaseserviceimpl</value>        </list>    </Property >    < property name="Interceptornames">        <list>            <value>Transactioninterceptor</value>        </list>    </Property ></Bean>

Then, run the test program again, we get the correct results, and some of the printed information is as follows:

debug:org.hibernate.engine.jdbc.internal.logicalconnectionimpl-obtaining JDBC Connection
debug:org.hibernate.engine.jdbc.internal.logicalconnectionimpl-obtained JDBC Connection
Debug:org.hibernate.engine.transaction.spi.abstracttransactionimpl-begin
Debug:org.hibernate.loader.loader-done Entity Load
User [Id=1, Name=newname]
User [Id=1, Name=newname2]
Debug:org.springframework.orm.hibernate4.hibernatetransactionmanager-initiating Transaction Commit
Debug:org.hibernate.engine.transaction.spi.abstracttransactionimpl-committing
This is basically consistent with the result of our use of programmatic transactions.

Expansion testing

Now, slightly modify the line in our interceptor:
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
We set it to read-only mode, at this time, call our test method, Queryupdateuser (1, "NewName3") ( because the previous test has changed the name to NewName2, in order to show different results, here the range NewName3 do the parameters ). Obviously, none of the previous add*,update*,delete* matches. The owning transaction must be started at this time key="*" . To run the method, we will find the result:

User [Id=1, Name=newname2]
User [Id=1, Name=newname3]
This seems to be consistent with the results we did not set ReadOnly, but we run again, the program does not throw an exception, and we find that the result is still:
User [Id=1, Name=newname2]
User [Id=1, Name=newname3]
It means that our changes are not actually in effect! At this point, I look at the debug information, found in:
Debug:org.hibernate.engine.transaction.spi.abstracttransactionimpl-begin the message with one more line:
debug:org.springframework.jdbc.datasource.datasourceutils-setting JDBC Connection [jdbc:mysql://localhost:3306/yc , [email protected], MySQL Connector Java] Read-only
Indicates that the current transaction is indeed read-only mode

Induction

Here alone out of the readonly to analyze, mainly for the actual development may encounter trouble. Imagine that we have the wrong read-only attribute configured. But we didn't find out, and when we tried to do the corresponding write data operation , we found that the program did not appear abnormal, but the data can not be written in any way. It's time to take a good look at our read-only properties and have to go where it shouldn't be!

Spring Learning Note (22) declarative transaction configuration, readonly Invalid write no exception

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.