1. Reflect transactions through examples
1.1 Build two tables from a database
The sale table stores the sales records, the id represents the number of the sales records, and the primary key is the automatic growth. gid is the number of goods purchased; num is the quantity of goods purchased. Initially, there is no data in the sale table. (
The goods table stores specific information about each item. id is the commodity number, the primary key; Name is the name of the commodity; amount is a stock of goods; Price is the unit price of a commodity.
1.2 Maven dependencies (pom.xml) needed to join a project
<dependencies> <!--Test class dependency--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- Spring rely on--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- spring Transaction Dependency--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- mybatis rely on--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <!-- spring and mybatis Integrate--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <!-- mysql drive--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency> <!-- Connection Pool of Ali--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory><!--In the directory--> <includes><!--Include under directory.properties,.xml All files will be scanned to--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
1.3 Write entity classes (Goods class, Sale class)
package com.liuhaiyang.entity; public class Goods { //Commodity number, primary key private Integer id; //Commodity Name private String name; //Commodity Inventory private Integer amount; //item pricing private Float price; //set and get, tostring, parametric construction, parametric construction }
package com.liuhaiyang.entity; public class Sale { //Primary key private Integer id; //id of the item purchased private Integer gid; //Quantity of goods purchased private Integer num; //set and get, tostring, parametric construction, parametric construction }
1.4 Write dao interfaces and corresponding mapper mapping files
1.4. 1 dao interface and mapper file corresponding to commodity entity class Goods
package com.liuhaiyang.dao; import com.liuhaiyang.entity.Goods; public interface GoodsDao { //Query commodities based on commodity id Goods selectById(Integer id); //The goods parameter indicates the id of the item purchased and the quantity of the item purchased //ID commodity id:amount: quantity of this item purchased this time int updateGoods(Goods goods); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.liuhaiyang.dao.GoodsDao"> <!--Use insert,uodate,delete,select Label Writing sql--> <select id="selectById" resultType="com.liuhaiyang.entity.Goods"> select * from goods where id=#{id} </select> <update id="updateGoods"> update goods set amount=amount-#{amount} where id=#{id} </update> </mapper>
1.4. 2. Sales record entity class Sale dao interface and mapper file
package com.liuhaiyang.dao; import com.liuhaiyang.entity.Sale; public interface SaleDao { int intsertsale(Sale sale); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.liuhaiyang.dao.SaleDao"> <!--Use insert,uodate,delete,select Label Writing sql--> <insert id="intsertsale" > insert into sale(gid,nums) values (#{gid},#{nums}) </insert> </mapper>
1.5 Write MyBatis Main Profile
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- Set Log--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!-- alias--> <!-- <typeAliases>--> <!-- <package name="com.liuhaiyang.entity"/>--> <!-- </typeAliases>--> <!--Specify Other mapper File location to find other files sql Sentence--> <mappers> <!-- <mapper resource="com/lhy/dao/studentDao.xml"/>--> <package name="com.liuhaiyang.dao"/> </mappers> </configuration>
1.6 Define exception classes (runtime exceptions)
This exception class is mainly used to handle the exceptional information that occurs when purchasing a commodity, whether or not there is an inventory or a commodity.
package com.liuhaiyang.excetion; //Runtime Exceptions public class NotException extends RuntimeException{ public NotException() { super(); } public NotException(String message) { super(message); } }
1.7 Define Service interfaces and corresponding implementation classes
package com.liuhaiyang.service; public interface BuyGoodsService { // Goods purchased ID means goods purchased ID num means the quantity of goods purchased void buyboods(Integer goodsid,Integer num); }
1.7.1 @Transactional control transaction
All of the optional properties for @Transactional are as follows:
1. propagation: Used to set transaction propagation properties. The property type is the Propagation enumeration, and the default value is Propagation.REQUIRED.
2. isolation: Used to set the isolation level of a transaction. The attribute type is the Isolation enumeration and the default value is Isolation.DEFAULT.
3. readOnly: Sets whether the method is read-only for database operations. The property is boolean and the default value is false.
4. timeout: Sets the timeout period for this operation to connect to the database. The unit is seconds, the type is int, and the default value is -1, which means there is no time limit.
5. rollbackFor: Specifies the exception class that needs to be rolled back. The type is Class[], and the default is an empty array. Of course, if there is only one exception class, you can not use arrays.
6. rollbackForClassName: Specifies the exception class name that needs to be rolled back. The type is String[], and the default is an empty array. Of course, if there is only one exception class, you can not use arrays.
7. noRollbackFor: Specifies an exception class that does not require rollback. The type is Class[], and the default is an empty array. Of course, if there is only one exception class, you can not use arrays.
8.noRollbackForClassName: Specifies the exception class name that does not require rollback. The type is String[], and the default is an empty array. Of course, if there is only one exception class, you can not use arrays. (
It is important to note that if @Transactionalis used on a method, it can only be used on a public method. For other non-public methods, with the comment @Transactional, Spring does not error, but does not weave the specified transaction into the method. Because Spring ignores the @Transaction annotation on all non-public methods. If the @Transaction annotation is on a class, it means that all methods on that class will be woven into transactions at execution time.
package com.liuhaiyang.service.impl; import com.liuhaiyang.dao.GoodsDao; import com.liuhaiyang.dao.SaleDao; import com.liuhaiyang.entity.Goods; import com.liuhaiyang.entity.Sale; import com.liuhaiyang.excetion.NotException; import com.liuhaiyang.service.BuyGoodsService; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; public class BuyGoodsServiceImpl implements BuyGoodsService { private GoodsDao goodsDao=null; private SaleDao saleDao=null; public void setGoodsDao(GoodsDao goodsDao) { this.goodsDao = goodsDao; } public void setSaleDao(SaleDao saleDao) { this.saleDao = saleDao; } // Transaction Notes /*@Transactional Put above the public method to indicate that the method has transactional functionality. Note that it cannot be added when it is private, but only when it is public * Features: 1) Transactions provided by the spring framework itself * 2)Suitable for small and medium-sized projects - change in code * 3)Easy to use and high efficiency */ /* First way @Transactional( propagation = Propagation.REQUIRED, // Runtime exception rollback for specified propagation behavior value isolation = Isolation.DEFAULT, //Represents isolation level readOnly = false,timeout = 20, // readOnly,Read-only or not, default is false timeout for timeout rollbackFor = { NullPointerException.class,NotException.class} //Rollback is required when an exception occurs )*/ /* Second way: @Transactional( propagation = Propagation.REQUIRED, //Indicates that there is always a transaction isolation = Isolation.DEFAULT, //Represents isolation level readOnly = false,timeout = 20) rollbackFor Use: 1)The framework first checks if the exception thrown by the method is in the rollbackFor s array, if it must be rolled back. 2)If the exception thrown by the method is not in the rollbackFor array, the framework continues to check if the exception thrown is in a RuntimeException. If it is a RuntimeException, it must be rolled back In special cases, the first is used, for example, when a SqlException IOException is thrown, a non-runtime exception can be used as the first rollbackFor={SQLException.class,IOException.class} */ //Third, @Transactional means that all are defaults, and REQUIRED means that rollback to default when an exception occurs @Transactional @Override public void buyboods(Integer goodsid, Integer num) { System.out.println("buy How to start!!!"); //Sales record Sale sale=new Sale(); sale.setQid(goodsid); sale.setNums(num); saleDao.intsertsale(sale); //Query commodities Goods goods1=goodsDao.selectById(goodsid); if (goods1== null){ throw new NullPointerException(goods1+"Commodity does not exist"); } else if (goods1.getAmount()<num){ throw new NotException(goods1+"Insufficient quantity of goods"); }else { System.out.println(goods1); } //Update Inventory Goods goods=new Goods(); goods.setId(goodsid); goods.setAmount(num); goodsDao.updateGoods(goods); System.out.println("buy Method completed!!!"); } }
1.8 Define Spring Profile
1.8. 1 Introduce external property profile (jdbc.properties)
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8 jdbc.username=root jdbc.password=123456
1.8. 2 Declare data source, SqlSessionFactory object, read mapper file, etc.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- Load import external property profile--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--Declare Data Source DataSource There can be multiple data sources--> <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!--statement SqlSessionFactoryBean,Inside this class, create SqlSessionFactory--> <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--specify data source --> <property name="dataSource" ref="myDataSource"/> <!--Appoint myBatis Main Profile Resource Can be used directly value Attribute Assignment--> <property name="configLocation" value="classpath:mybatis.xml"/> </bean> <!--statement MapperScannerConfiguration SqlSession.getMapper(StudentDao.class) MapperScannerConfigurer Effect: loop basePackage Represented package, find each interface in the package, call SqlSession.getMapper Put each dao Interfaces are created dao Object, dao Proxy object methods into containers. Amount to: ApplicationContext ctx=... SqlSessionFactory sqlSessionFactory=ctx.getBean("factory"); for(Interface: com.liuhaiyang.dao){ Interface Object=session.getMapper(Interface) springMap.put(Object name, object) } --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- Appoint sqlsessionFactory Name of object--> <property name="sqlSessionFactoryBeanName" value="factory"/> <!-- Specify the base package, dao Package name of the interface--> <property name="basePackage" value="com.liuhaiyang.dao"/> </bean> <!-- statement service--> <bean id="buyselect" class="com.liuhaiyang.service.impl.BuyGoodsServiceImpl"> <property name="goodsDao" ref="goodsDao"/> <property name="saleDao" ref="saleDao"/> </bean> <!-- <context:component-scan base-package="com.liuhaiyang.service"/>--> <!-- Declare transaction control--> <!-- Declare Transaction Manager id It can be any value, preferably transactionManager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- specify data source DataSources--> <property name="dataSource" ref="myDataSource"/> </bean> <!-- Turn on Transaction Annotation Driver: Tell the framework that using annotations to manage transactions is typically tx Ending Attributes: transaction-manager Specify Transaction Manager's id There can be multiple id(You can also have multiple data sources) --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
1.9 Define test classes
1.9. 1 Test Class 1
import com.liuhaiyang.service.BuyGoodsService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test { @Test public void test01(){ String config="application.xml"; ApplicationContext app=new ClassPathXmlApplicationContext(config); BuyGoodsService buy=(BuyGoodsService) app.getBean("buyselect"); buy.buyboods(1001,20); } }
Result Screenshot:
1.9. 2 Test Class 2 (Exception)
@Test public void test01(){ String config="application.xml"; ApplicationContext app=new ClassPathXmlApplicationContext(config); BuyGoodsService buy=(BuyGoodsService) app.getBean("buyselect"); buy.buyboods(1001,50); }
Result Screenshot:
Database
2. Use the AspectJ framework to control transactions
The disadvantage of configuring transaction agents with XML is that each target class needs to be configured with a transaction agent. When there are more target classes, the configuration file becomes very bloated.
Use XML Configuration Advisor to automatically generate a transaction proxy for each class that matches the entry point expression. The usage is simple, simply delete the configuration of the transaction proxy in the previous code and replace it with the following.
The steps to control transactions in this way are as follows:
In pom. Add spring-aspects dependency to XML
Declare the contents of a transaction in the spring configuration file: 1 Declare the transaction manager; (2) Declare transaction attributes required by business methods; 3. Declare the entry point expression.
Most of the code is the same as using the comment (@Transactional) above. Only Spring's configuration file has changed.
Delete the declare transaction annotation driver in the spring configuration file in the first method and replace it with the code below.
<!-- 2.Declare transaction attributes of the business party (isolation level, propagation behavior, timeout) id:Give the business method configuration transaction segment code a name, unique value (customizable) transaction-manager: Transaction Manager id --> <tx:advice id="selectAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- Give a specific business method the transaction properties he needs name: Name of business method. To configure name Value of: 1.Name of business method: 2.With wildcards(*)Method Name 3.Use* propagation: Value specifying propagation behavior isolation: Isolation Level read-only: Read-only or not. Default is false timeout Represents a timeout rollback-for: Specify a list of rollback exception types, using the exception fully qualified name--> <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT" read-only="false" timeout="20" rollback-for="com.liuhaiyang.excetion.NotException,java.lang.NullPointerException"/> <!-- Represents all of the buy Beginning business method for transactional operations--> <!-- <tx:method name="buy*" Wait/>--> <!-- Individual uses other than the above represent all, and other uses represent methods other than--> <!-- <tx:method name="*" Wait/>--> </tx:attributes> </tx:advice> <!-- Declare entry point expressions: represent classes in those packages, method parameters and transactions in classes--> <aop:config> <!-- Declare entry point expression expression: Breakthrough point expressions to express methods in those classes and classes id: Represents the name of the entry point expression, unique value(Any value)--> <aop:pointcut id="servicePointcut" expression="execution(* *..service.*(..))"/> <!-- Associate entry point expressions with transaction notifications--> <aop:advisor advice-ref="selectAdvice" pointcut-ref="servicePointcut"/> </aop:config>
3 @Transactional annotations and AspectJ framework features
1. Use the @Transactional annotation
1. Transaction control provided by the Spring framework itself.
2. Suitable for small and medium-sized projects.
3. Easy to use and high efficiency.
2. Using the AspectJ framework
Disadvantages: Difficult to understand and complex to configure.
Advantage: Code and transaction configurations are separate. Controls the transaction without modifying its source code. Ability to quickly understand and control the entire transaction of a project, suitable for large projects.