This is the 14th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
Spring integration Mybatis
Integrated thinking
Spring can integrate many frameworks, which is Spring’s advantage. By integrating other frameworks, it is easier to develop and integrate the IOC function of Spring
To use the Mybatis step
To use MyBatis, we need to create some objects in myBatis framework, using these objects to use myBatis functions, we can give these objects to Spring to manage, need to use the container can be taken
- A proxy object with a DAO is required
- SQLSessionFactory is required to create the SQLSessionFactory object in order to obtain the SqlSession object using openSession()
- DataSource DataSource object
Integration of mybatis
Generate database tables
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL.PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Copy the code
Add dependency XML
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<! - spring dependent - >
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.12</version>
</dependency>
<! - spring transaction -- -- >
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.12</version>
</dependency>
<! --springjdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.12</version>
</dependency>
<! - mybatis dependence - >
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<! - Mybatis - spring depend on -- -- >
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<! Mysql > select * from 'mysql';
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<! - druid dependence - >
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
Copy the code
Entity class
public class User { private int id; //id private String name; // Name private String PWD; Public int getId() {return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + ''' + ", pwd='" + pwd + ''' + '}'; }}Copy the code
UserMapper.java
@Mapper
public interface UserMapper {
public int InsertUser(User user);
public User finfdById(Integer id);
}
Copy the code
UserMapper.xml
<! DOCTYPEmapper
PUBLIC "- / / mybatis.org//DTD Mapper / 3.0 / EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<! -- Bind mapping interface -->
<mapper namespace="org.study.Mapper.UserMapper">
<insert id="InsertUser" >
INSERT INTO user
( id, name,pwd)
VALUES(#{id}, #{name}, #{pwd});
</insert>
<select id="finfdById" resultType="user">
select * from user where id= #{id}
</select>
</mapper>
Copy the code
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public void insertUser(User user) {
userMapper.InsertUser(user);
}
@Override
public User findById(Integer id) {
User user = userMapper.finfdById(id);
returnuser; }}Copy the code
@Service
public interface UserService {
public void insertUser(User user);
public User findById(Integer id);
}
Copy the code
Mybatis configuration file
<? The 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> <settings> <! -- Print query statement --> <setting name="logImpl" value="STDOUT_LOGGING" /> </ Settings > <typeAliases> <package name="org.study.domain"/> </typeAliases> <mappers> <package name="org.study.Mapper"/> </mappers> </configuration>Copy the code
Spring configuration file
<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"
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">
<! Declare data source -->
<context:annotation-config />
<context:component-scan base-package="org.study"/>
<bean id="MyDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_test? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC"></property>
<property name="name" value="root"></property>
<property name="password" value="root"></property>
</bean>
<! Declare the SqlSessionFactoryBean to create an SqlSessionFactory inside this class.
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<! -- Specify data source -->
<property name="dataSource" ref="MyDataSource"></property>
<! Mybatis master configuration file -->
<property name="configLocation" value="classpath:mybatsi-config.xml"></property>
</bean>
<! - a statement MapperScannerConfigurer -- -- >
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<! - specifies SqlSessionFactoryBean -- -- >
<property name="sqlSessionFactoryBeanName" value="factory"></property>
<! -- Know the package name -->
<property name="basePackage" value="org.study.Mapper"></property>
</bean>
</beans>
Copy the code
The test class
@Test
public void shouldAnswerWithTrue()
{
String config ="application.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(config);
UserService service = (UserServiceImpl) applicationContext.getBean("userServiceImpl");
User user1 = new User();
user1.setId(13);
user1.setName("liming");
user1.setPwd("12345");
service.insertUser(user1);
User user = service.findById(13);
System.out.println(user);
}
Copy the code
The output
The Spring transaction
An overview of the
A transaction is a collection of columns of SQL statements that either all succeed or all fail.
When to use transactions
An operation can be successful only after multiple Sql statements are completed
Where are transactions described
On the business approach side
public class dao(a){
public void insertA(a);
public void insertB(a):}public void Service(a){
@Autowired
privateThe dao dao1;// Transaction under here
public void insertAB(a){ dao1.insertA(); dao1.insertB(); }}Copy the code
Spring transaction manager
Different database access technology, transaction processing is different,Spring unified management of transactions, the different data access technology transaction processing unified, using the Spring transaction manager, management of different database access technology transaction processing, only need to master the Spring transaction processing a scheme, Transaction management can be implemented using different database access technologies.
The spring framework using the transaction manager management object, the transaction manager interface is PlatformTransacationManger, defines the operation of the transaction, is mainly the commit rollback () () the transaction manager has a lot of implementation class, a database access count with an implementation class, There are implementation classes that specifically do things like commit, roll back. The transaction manager is DataSourceTranactionManager JDBC and mmybatis. Hibernate transaction manager is hibernateTranactionManager
The teacher draws a picture of the way Spring manages transactions, the business code is submitted by the normal executive board, and rolled back when an exception occurs at runtime
The business code is being submitted to the EXECUTIVE board and rolled back when an exception occurs at runtime
Abnormal classification
- Error Indicates a critical Error that rolls back the transaction
- Exception Exception class, which can handle exceptions
- Runtime exception: RuntimeException and its subclasses are run-time exceptions thrown during program execution. Common examples include NullPointException. IndexOutOfBoundsException array bounds ClassCastException force changing anomaly
- Checked exception: An exception that must be checked when writing Java code, such as IOException. SQLException
Whenever a runtime exception transaction rollback occurs in a run method, the other case (normal execution method, checked exception) commits the transaction
Transactions use AOP’s wrap around advice
Circular notification: Can be enhanced both before and after the target method without modifying the code, the transaction is opened before the business code, the transaction is committed after the business code, and the transaction is rolled back after an exception Catch occurs
The TransactionDefinition interface TransactionDefinition
Three types of constants are defined, and properties related to transaction control are defined
- Isolation level
- Propagation behavior
- Time out of something
Isolation level
Isolation level: Controls the degree of influence between things
These constants all start with ISOLATION_. Such as ISOLATION_XXX.
- DEFAULT: Use the DEFAULT transaction isolation level of DB. MySql defaults to REPEATABLE_READ; Oracle defaults to READ_COMMITTED. (Read submitted)
- READ_UNCOMMITTED: Read is not committed. No concurrency issues were resolved.
- READ_COMMITTED: Reads committed. Solve dirty read, there is no repeat read and unreal read.
- REPEATABLE_READ: Repeatable read. Solve dirty read, unrepeatable read, phantom read
- SERIALIZABLE: serialization. There is no concurrency problem.
timeout
The value is in seconds. The default value is -1, which indicates the longest execution time of a service method. If the execution is not complete, the transaction will be rolled back
Propagation behavior
Transactions are passed and used between methods during the execution of business methods, and may indicate whether the method is transacted or not, with seven values beginning with PROPAGATION_XXXX
-
PROPAGATION_REQUIRED Default propagation behavior, which supports the current transaction if one exists when a method executes. If there are no transactions, a new transaction is started and executed in the new transaction
-
PROPAGATION_SUPPORTS, if a transaction exists, supports the current transaction. If there is no transaction, non-transactional execution. However, for transactionally-synchronized transaction managers, PROPAGATION_SUPPORTS is slightly different from not using transactions.
-
PROPAGATION_REQUIRES_NEW always opens a new transaction. If a transaction already exists, suspend the existing transaction.
-
PROPAGATION_MANDATORY The current transaction is supported if a transaction already exists. If there is no active transaction, an exception is thrown.
-
PROPAGATION_NOT_SUPPORTED is always executed non-transactionally and suspends any existing transactions.
-
PROPAGATION_NEVER is always executed non-transactionally, and an exception is thrown if an active transaction exists
-
Run in a nested transaction, PROPAGATION_NESTED, if an active transaction exists. If there is no active transaction, then the TransactionDefinition. PROPAGATION_REQUIRED properties is carried out
Code testing – without transactions
Simulate the purchase order table to add goods, inventory table to subtract inventory
Prepare two tables
CREATE TABLE `sale` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`gid` int(11) DEFAULT NULL,
`nums` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8
CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`amount` int(11) DEFAULT NULL,
`price` float DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8
Copy the code
Entity class
@Data
public class Sale {
private Integer id;
private Integer gid ;
private Integer nums;
}
Copy the code
@Data
public class Goods {
private Integer id;
private String name;
private Integer amount;
private float price;
}
Copy the code
Spring configuration file
<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">
<! Declare data source -->
<context:annotation-config />
<context:component-scan base-package="com.study"/>
<bean id="MyDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_test? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC"></property>
<property name="name" value="root"></property>
<property name="password" value="root"></property>
</bean>
<! Declare the SqlSessionFactoryBean to create an SqlSessionFactory inside this class.
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<! -- Specify data source -->
<property name="dataSource" ref="MyDataSource"></property>
<! Mybatis master configuration file -->
<property name="configLocation" value="classpath:mybatsi-config.xml"></property>
</bean>
<! - a statement MapperScannerConfigurer -- -- >
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<! - specifies SqlSessionFactoryBean -- -- >
<property name="sqlSessionFactoryBeanName" value="factory"></property>
<! -- Know the package name -->
<property name="basePackage" value="com.study.mapper"></property>
</bean>
</beans>
Copy the code
Mybatis configuration file
<! DOCTYPEconfiguration
PUBLIC "- / / mybatis.org//DTD Config / 3.0 / EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<! Print query statement -->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<typeAliases>
<package name="com.study.domain"/>
</typeAliases>
<mappers>
<package name="org.study.Mapper"/>
</mappers>
</configuration>
Copy the code
Mapper and XML
<! DOCTYPEmapper
PUBLIC "- / / mybatis.org//DTD Mapper / 3.0 / EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<! -- Bind mapping interface -->
<mapper namespace="com.study.mapper.saleMapper">
<insert id="buyGoods" >
insert into sale ( gid, nums)
VALUES(#{gid}, #{nums});
</insert>
</mapper>
Copy the code
@Mapper
public interface saleMapper {
public void buyGoods(Sale sale1);
}
Copy the code
<! DOCTYPEmapper
PUBLIC "- / / mybatis.org//DTD Mapper / 3.0 / EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<! -- Bind mapping interface -->
<mapper namespace="com.study.mapper.goodsMapper">
<select id="findById" resultType="goods">
select * from goods where id=#{id}
</select>
<update id="updateAmount" >
update goods set amount = amount - #{amount} where id= #{id}
</update>
</mapper>
Copy the code
@Mapper
public interface goodsMapper {
public Goods findById(Integer id);
public void updateAmount(Goods good);
}
Copy the code
Business methods
public interface BuyService {
void Buy(Integer id,Integer num);
}
Copy the code
@Autowired private goodsMapper goodsMapper1; @Autowired private saleMapper saleMapper1; @override public void Buy(Integer id, Integer num) {system.out.println (" Buy "); Sale sale = new Sale(); sale.setGid(id); sale.setNums(num); saleMapper1.buyGoods(sale); Goods byId = goodsMapper1.findById(sale.getGid()); If (byId == null){throw new NullPointerException(" item not found "); } else if(byid.getAmount ()< sale.getnums ()){throw new MyException(" inventory is low "); } Goods goods = new Goods(); goods.setAmount(sale.getNums()); goods.setId(sale.getGid()); goodsMapper1.updateAmount(goods); }Copy the code
The test class
public void shouldAnswerWithTrue()
{
String config ="application.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(config);
BuyService service = (BuyService) applicationContext.getBean("buyServiceImpl");
service.Buy(1001,1000);
}
Copy the code
I did not add transaction to the above code to buy the product without the error, but the information of the first step order table will still be saved.
The Spring framework uses its own annotation, @Transaction, to control transactions
@Transaction uses attributes of annotations to control transactions, isolation levels, propagation behavior, and timeouts
@ the attribute of the Transaction
- Propagation: Propagation behavior of things. It uses the enumeration value propagation.REQUIRED
- Isolation: Isolation level The Isolation enumeration class is used to indicate the isolation level by DEFAULT isolation.default
- ReadOnly: Boolean specifies whether a database operation is read-only. The default value is false
- Timeout: indicates the transaction timeout. The default value is -1. The unit is seconds
- RollBackFor: indicates the exception type of the rollback
- RollBackForClassName: list of exception classes that are rolled back. Value is the name of the exception class, a String value
- NoRollackFor: Data exception that does not need to be rolled back. It is of class type
- NoRollBackForClassName: Data exception that does not need to be rolled back. The value is a String
location
- On top of business methods, on top of public methods
- Above the class
The characteristics of
- Spring’s own transaction management
- Suitable for small and medium projects
- Easy to use
Use annotations to implement transactions
Declare the transaction manager and enable annotations in the Spring configuration file
<! Declare transaction controller -->
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<! -- Specify data source for transaction operation -->
<property name="dataSource" ref="MyDataSource"></property>
</bean>
<! -- Turn on the transaction annotation driver and tell the framework to use annotations to manage transactions transactions-manager: specify the id of the transaction manager proxy-target-class: true if the class-based proxy will work (requires the Cglib library), false or omit this attribute -->
<tx:annotation-driven transaction-manager="TransactionManager" proxy-target-class="true"></tx:annotation-driven>
Copy the code
Add the @Transactional annotation and configure the attributes on the business code. You can also implement transactions by writing @Transactional directly, using the default values. RollbackFor specifies the exception type to be rolled back. If not, all RuntimeException subclasses will be rolled back. What exceptions can be specified that do not need to be rolled back
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
timeout = 20,
readOnly = false,
rollbackFor ={NullPointerException.class,MyException.class}
)
Copy the code
Declarative transaction
<! Declarative transaction -->
<! -- Declare transaction manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="MyDataSource"></property>
</bean>
<! Declare transaction properties of the business method (isolation level, propagation behavior, timeout) -->
<tx:advice id="Advice" transaction-manager="transactionManager">
<! Add something to a specific business method -->
<tx:attributes>
<! 1. The name of the service method 2. The name of the service method with some wildcards 3. Isolation Level Read -only: read-only or not timeout: timeout period rollback-for: specifies the exception type for rollback -->
<tx:method name="Buy" propagation="REQUIRED" isolation="DEFAULT" read-only="false" timeout="20"/>
<! -- Business method with naming rules -->
<tx:method name="add*" propagation="REQUIRED"></tx:method>
<tx:method name="update*" propagation="REQUIRED"></tx:method>
<tx:method name="delect*" propagation="REQUIRED"></tx:method>
<! -- Other than the above * -->
<tx:method name="*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
<aop:config>
<! Declare pointcut expression expression: declare the transaction ID names of the methods in those classes -->
<aop:pointcut id="servicePoint" expression="execution(* *.. service.. *. * (..) )"/>
<! Pointcut expressions and transaction notifications -->
<aop:advisor advice-ref="Advice" pointcut-ref="servicePoint"></aop:advisor>
</aop:config>
Copy the code