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&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;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
  1. 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
  2. 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&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;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