spring Things - Development Course

Keywords: Programming Spring Mybatis xml JDBC

1. spring

spring defines things by three APIs

Transaction Definition
Platform Transaction Manager manages things, submits or rolls back
Transaction Status represents the state in which something is running

Definition of Things Transaction Definition

public interface TransactionDefinition {
	//Isolation level
	int getIsolationLevel();
	//Communication behavior
	int getPropagationBehavior();
	//timeout
	int getTimeout();
	//readOnly
	boolean isReadOnly();
}

DefaultTransaction Definition is the default implementation class, which has a subclass Transaction Template. Transaction Template's execute method can directly program things.

Management of Things Platform Transaction Manager

public interface PlatformTransactionManager {
	//Query the current state of things
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
	//Submission of things
    void commit(TransactionStatus var1) throws TransactionException;
	//rollback transaction
    void rollback(TransactionStatus var1) throws TransactionException;
}

Realization:
Data Source Transaction Manager: For data persistence operations using JDBC and iBatis.
Hibernate Transaction Manager: Suitable for data persistence operations using Hibernate.
JpaTransaction Manager: Applicable to data persistence operations using JPA.
Rabbit Transaction Manager Rabbitmq supports integration with spring things
There are also JtaTransaction Manager, JdoTransaction Manager, Jms Transaction Manager, and so on.

Transaction Status

public interface TransactionStatus extends SavepointManager, Flushable {
	//Is it a new thing (to participate in an existing thing, or when nested, the first layer calls nothing nesting to open things)?
    boolean isNewTransaction();

	//Is there a preservation point?
    boolean hasSavepoint();
	
	//Setting things to roll back
    void setRollbackOnly();

	//Whether to roll things back or not
    boolean isRollbackOnly();

	//Refreshing the session of the current thread to the database has an impact on Hibernate/JPA sessions
    void flush();

	//Are things completed, submitted, or rolled back?
    boolean isCompleted();
}

Realization:

DefaultTransactionStatus,SimpleTransactionStatus

 

2. There are two ways to manage things with spring, programming and declarative. Let's look at two ways to implement it

2.1 Programming things:

There are two ways of programmable transaction management
1. Submit rollback items using Platform Transaction Manager
2. Use Transaction Template
Sample code:

@Service
public class ProgrammaticService {


    @Autowired
    private RuleDOMapper ruleDOMapper;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private TransactionDefinition txDefinition;

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void useTXManager(){

        TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
        boolean result = false;
        try {
            ruleDOMapper.insert(new RuleDO());
            transactionManager.commit(txStatus);
        } catch (Exception e) {
            transactionManager.rollback(txStatus);
            System.out.println("Transfer Error!");
        }
    }

    public void useTXTemplate(){
        transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus status) {
                ruleDOMapper.insert(new RuleDO());
                return 1;
            }
        });
    }

}


public class RuleDOMapper {

    SqlSession sqlSession;

    public int insert(RuleDO record){
        return sqlSession.insert(getNameSpace()+"insert",record);
    }

    public String getNameSpace(){
        return this.getClass().getName()+".";
    }
	//get set method
}

To configure:

<!-- Configure data source information -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://192.168.30.96:3306/test?autoReconnect=true&amp;useUnicode=true&amp;characterset=utf8"/>
        <property name="username" value="quanyan"/>
        <property name="password" value="quanyan888"/>
    </bean>

    <!-- To configure spring Of PlatformTransactionManager,Name is the default value -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- Object template -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>

    <!-- Definition of things -->
    <bean id="txDefinition" class="org.springframework.transaction.support.DefaultTransactionDefinition">
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
    </bean>

    <!-- To configure ibatis Mapping information -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"/>
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.masz.springtest.dao.*"/>
        <property name="sqlSessionTemplateBeanName" value="sqlSession"/>
    </bean>
	
	<!-- Definition mapper -->
	<bean id="ruleDOMapper" class="com.masz.springtest.dao.RuleDOMapper">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>

Test code:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:application-context.xml")
public class SpringTest {

    @Autowired
    ProgrammaticService programmaticService;

    @Autowired
    TransactionInterceptorTest transactionInterceptorTest;

    @Test
    public void programmaticTxTest(){
        programmaticService.useTXManager();
//        programmaticService.useTXTemplate();
    }
}

test result

2.2 Declarative Things

Spring's declarative transaction management is based on AOP at the bottom. Its essence is to intercept the method before and after, then create or join a transaction before the target method starts, and submit or roll back the transaction according to the implementation after the target method is executed. The above programmable things are template code. Since it's template code, spring has to solve it.

Comparisons between programmable and declarative transactions
1. Declarative transaction with additional configuration will do without adding transaction management code to the code. So it's more convenient to use than programmers, business code will not be "polluted" by things code.
2. The finest granularity of declarative things can only work at the method level, not at the code block level like programmatic transactions. You can also put the code blocks of declarative things into the way things are managed separately.
Realization:
    1,TransactionInterceptor
    2,TransactionProxyFactoryBean
3. Implementing declarative things based on <tx> namespaces
4, @Transactional annotation

2.2.1 Using Transaction Interceptor

Sample code:

/**
 * TransactionInterceptor Implementing declarative things, target classes
 */
public class TransactionInterceptorTarget {

    private RuleDOMapper mapper;

    public void save(){
        mapper.insert(new RuleDO());
    }
	//Get set method
}

Test code:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:application-context.xml")
public class SpringTest {

    @Resource(name = "transactionInterceptorTarget")
    TransactionInterceptorTarget transactionInterceptorTarget;

    @Resource(name = "transactionInterceptorTargetProxy")
    TransactionInterceptorTarget transactionInterceptorTargetProxy;

    @Test
    public void transactionInterceptorTest(){
        //Direct use is nothing.
        transactionInterceptorTarget.save();

        //Using proxy objects can be enhanced by things
        transactionInterceptorTargetProxy.save();
    }
}

Configuration (data source transactionManager, see the configuration above in the reference article):

<bean id="transactionInterceptor"  class="org.springframework.transaction.interceptor.TransactionInterceptor">
	<property name="transactionManager" ref="transactionManager"/>
	<property name="transactionAttributes">
		<!-- Define the attributes of things -->
		<props>
			<!-- Configure the object attributes or method wildcards used by the method name of the target class -->
			<prop key="save*">PROPAGATION_REQUIRED</prop>
		</props>
	</property>
</bean>

<!-- Target object, direct use is nothing.-->
<bean id="transactionInterceptorTarget" class="com.masz.springtest.transaction.TransactionInterceptorTarget">
	<property name="mapper" ref="ruleDOMapper"/>
</bean>

<!-- adopt ProxyFactoryBean Getting Enhanced Objects of Target Objects -->
<bean id="transactionInterceptorTargetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
	<!-- Proxy target class -->
	<property name="target" ref="transactionInterceptorTarget"/>
	
	<!-- Use interceptor Enhance  -->
	<property name="interceptorNames">
		<list>
			<idref bean="transactionInterceptor"/>
		</list>
	</property>
</bean>

Test results:
Use the target class directly without opening spring things

Open spring things using proxy classes

The disadvantage of using Transaction Interceptor is that there are too many configurations, each target class that uses things needs to be configured with a Transaction Interceptor and a ProxyFactoryBean.
spring also provides a Transaction ProxyFactory Bean that combines the configuration of Transaction Interceptor and ProxyFactory Bean to alleviate this problem.
 

2.2.2, Transaction ProxyFactoryBean Implementation

Sample code:

/**
 * TransactionProxyFactoryBean test
 */
public class ProxyFactoryBeanTestTarget {

    private RuleDOMapper mapper;

    public void save(){
        mapper.insert(new RuleDO());
    }
	
	//get set method
}

configuration file

<!-- Target object -->
<bean id="proxyFactoryBeanTestTarget" class="com.masz.springtest.transaction.TransactionInterceptorTarget">
	<property name="mapper" ref="ruleDOMapper"/>
</bean>

<!-- Surrogate object -->
<bean id="proxyFactoryBeanProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
	<property name="target" ref="proxyFactoryBeanTestTarget"/>
	<!-- Attributes of Things Management -->
	<property name="transactionManager" ref="transactionManager"/>
	<property name="transactionAttributes">
		<props>
			<!-- save The way to start is enhanced by things. -->
			<prop key="save*">PROPAGATION_REQUIRED</prop>
		</props>
	</property>
</bean>

Test code:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:application-context.xml")
public class SpringTest {

	//Use code objects to be enhanced by things
    @Resource(name = "proxyFactoryBeanProxy")
    TransactionInterceptorTarget proxyFactoryBeanProxy;

    @Test
    public void proxyFactoryBeanTest(){
        proxyFactoryBeanProxy.save();
    }
}

Test results:

Using TransactionProxyFactoryBean, a class also needs two configurations. And proxy classes need to be injected.

2.2.3. Implementing declarative things based on <tx> namespaces
Test code:

/**
 * tx Configuration namespace configuration testing
 */
public class TransactionTXNameSpaceTest {

    private RuleDOMapper mapper;


    public void add(){
        mapper.insert(new RuleDO());
    }
	//Getset method...
}

To configure:

<!-- Target object -->
<bean id="transactionTXNameSpaceTest" class="com.masz.springtest.transaction.TransactionTXNameSpaceTest">
	<property name="mapper" ref="ruleDOMapper"/>
</bean>

<!--  Declarative container transaction management  advice -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<!-- pointcut matching -->
		<tx:method name="add*" propagation="REQUIRED"/>
		<tx:method name="upd*" propagation="REQUIRED"/>
		<tx:method name="del*" propagation="REQUIRED"/>
		<tx:method name="*" read-only="true"/>
	</tx:attributes>
</tx:advice>

<aop:config expose-proxy="true">
	<!-- pointcut -->
	<aop:pointcut id="txPointcut" expression="execution(* com.masz.springtest.transaction..*.*(..))"/>
	<!-- Advisor -->
	<aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice"/>
</aop:config>

Test code:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:application-context.xml")
public class SpringTest {

    @Autowired
    TransactionTXNameSpaceTest transactionTXNameSpaceTest;

    @Test
    public void transactionTXNameSpaceTest(){
		//Direct use of target classes
        transactionTXNameSpaceTest.add();
    }
}

Test results:

As long as you configure the facets of the configuration, you can rest assured of using things to enhance.

4. Implementing declarative transactions based on @Transactional

Add configuration:

<! - Declarative transaction configuration based on @Transactional
<! -- The default value of the transaction-manager attribute is transactionManager, which can be omitted if the name of the transaction manager Bean is that value. >
<tx:annotation-driven transaction-manager="transactionManager"/>

The test is relatively simple, so I won't write it.

Attention should be paid to using @Transactional:
1. The @Transactional annotation can work on interfaces, interface methods, classes, and class methods, but it is not recommended to use the annotation on interfaces or interface methods because it will only take effect when using an interface-based proxy.
2. The @Transactional annotation should only be applied to the public method, which is determined by the nature of Spring AOP. If you use the @Transactional annotation on protected, private, or default visibility methods, it will be ignored and no exception will be thrown.
3. The @Transactional approach must be annotated with @Transactional on every method or class that needs to use transactions. Although the rules of most transactions may be consistent, they cannot be reused for @Transactional and must be specified one by one.

End:
Although the above list of four declarative transaction management methods, but this division is only for easy understanding, in fact, the implementation of the background is the same, but the way users use it is different.

Posted by williamZanelli on Sat, 26 Jan 2019 23:09:15 -0800