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 use a programmatic approach to configure transactions, and the advantage is that we have very strong control over each approach. For example, what business do I need to use, where to assume that an exception needs to be rolled back, etc. Able to perform very fine-grained configurations. But in the actual development. We may not need such a fine-grained configuration.

On the other hand, suppose our project is very large and the service layer method is very many. Configuring transactions separately for each method is also a tedious task. And can also cause a lot of repeated 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 transaction configuration.

Example analysis

The declarative transaction configuration principle is equivalent to the use of surround enhancement, intercept target methods, and weave into our transactions before their invocation. The transaction is then committed or rolled back at the end of the call based on execution. 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"><!--Configure bean--> to be proxied        <list>            <value>Mybaseserviceimpl</value>        </list>    </Property >    < property name="Interceptornames"><!--declaring interceptors --        <list>            <value>Transactioninterceptor</value>        </list>    </Property ></Bean><!--tested to the relevant dependency-<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 specific analysis

In the instance we configure the interceptor and the proxy generator.

When configuring the Transactioninterceptor transaction property, key corresponds to the method name, and we use add* to match all the methods in the target class that begin with add to intercept the configuration transaction against the method of the target object class. We intercept based on the order in which the attributes are defined, assuming that it is intercepted by the key="add*" transaction property, even if there is a key="*"能够匹配随意方法,也不会再次被拦截。 transaction attribute format in the tag such as the following:
传播行为 [。隔离级别] [,仅仅读属性] [。超时属性] [,-Exception] [,+Exception]
In addition to the propagation behavior, the others are optional.

Each property description is visible in the following table

Properties Description
Propagation behavior The value must start 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 The value must start with "Isolation_", including: Isolation_default, isolation_read_committed, isolation_read_uncommitted, ISOLATION_ Repeatable_read, isolation_serializable. A total of five values are taken.

Read-only properties Assuming the transaction is read-only, we can specify a read-only property, using "ReadOnly".

Otherwise we do not need to set this property.

Timeout property The value must begin with "Timeout_", followed by a value of type int. Represents the time-out period, in seconds.

+exception Even if these types of exceptions are thrown in the transaction, the transaction is still committed normally. You must precede each exception's name with a "+". The name of the exception can be part of the class name. For example, "+runtimeexception", "+tion" and so on. You can specify multiple at the same time. 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. For example, "-runtimeexception", "-tion" and so on. Can specify multiple at the same time, such as-exception1,-exception2

As can be seen from the configuration file, we are able to configure multiple interceptors and multiple beans to fit different transactions. This declarative transaction is very convenient to use.

Service Layer Configuration

After using declarative transactions, compare to the previous article example. Our service layer needs to be rewritten as:

 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 at the same time removed the intrusive configuration of the transaction (in each method). Of course, the advantage of a programmatic transaction is the ability to configure the transaction fine-grained into each method. When the business of most of our methods is still the same. We are able to use declarative transactions. For those that need to be configured independently, 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, perform 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");    }}

To perform a test method, 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 own defined service implementation class. The reason is that because our beannameautoproxycreator does not use the Cglib proxy by default, 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. In the 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, after the test procedure is executed, we get the correct results, and some of the information is printed such as the following:

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.

Expand Test

Now. Change the line slightly 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, there is a range of NewName3 to do the number of parameters ). Obviously. None of the preceding add*,update*,delete* can match. This is the time when the key="*" owning transaction must start. Execution 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 do it again, the program does not throw an exception, and we find 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 time, look at the debug information, hair now:
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 a read-only mode

Induction

Here alone out ReadOnly to analyze. Mainly for the actual development of the problems that may be encountered. Imagine that we were wrong to just read the attribute configuration on one day. 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.