Spring 07 -- integrating Mybatis and declarative transactions

Posted by Buyocat on Wed, 09 Feb 2022 03:45:10 +0100

1, Integrate Mybatis

Mybatis spring new package

Environment construction

	<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <!--Spring If you operate the database, you also need one spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!--aop Weave in-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
    </dependencies>

MyBatis Spring will help you seamlessly integrate MyBatis code into Spring.

Mode 1

1. Write data source

		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.3</version>
        </dependency>

2.sqlSessionFactory

To use MyBatis with Spring, you need to define at least two things in the Spring application context: a SqlSessionFactory and at least one data mapper class.

In mybatis Spring, SqlSessionFactory bean can be used to create SqlSessionFactory. To configure the factory bean, you only need to put the following code in the XML configuration file of Spring

Write spring Dao xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--DataSource:use spring Data source replacement for mybatis Configuration of  c3p0 dbcp
    Use here Spring Provided jdbc:org.springframework.jdbc.datasource-->

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/shy?useSSL=true&amp;
                useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--binding mybatis-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/shy/dao/*.xml"/>
    </bean>

    <!--SqlSessionTemplate:That's what we use sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--Only constructor injection can be used sqlSessionFactory,Because he didn't set method-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userMapper" class="com.shy.dao.UserMapperImpl">
        <property name="sqlSessionTemplate" ref="sqlSession"/>
    </bean>
</beans>

SqlSessionFactory requires a DataSource. This can be any DataSource. You only need to configure it as you configure other Spring database connections.

In the basic MyBatis usage, SqlSessionFactory is created through SqlSessionFactory builder. In MyBatis spring, SqlSessionFactoryBean is used to create.

In MyBatis, you can use SqlSessionFactory to create sqlsessions. Once you get a session, you can use it to execute mapped statements, commit or roll back connections, and finally close the session when it is no longer needed.

SqlSessionFactory has a unique required attribute: DataSource for JDBC. This can be any DataSource object, and its configuration method is the same as that of other Spring database connections.

A common attribute is configLocation, which is used to specify the XML configuration file path of MyBatis. It is very useful when you need to modify the basic configuration of MyBatis. Generally, the basic configuration refers to < Settings > or < typealiases > elements.

It should be noted that this configuration file does not need to be a complete MyBatis configuration. Specifically, any Environment configuration (), data source () and MyBatis's transaction manager () will be ignored. SqlSessionFactoryBean will create its own MyBatis Environment configuration and set the value of custom Environment as required.

SqlSessionTemplate is the core of mybatis spring. As an implementation of SqlSession, this means that it can be used to seamlessly replace the SqlSession already in use in your code.

The template can participate in the transaction management of Spring, and because it is thread safe, it can be used by multiple mapper classes. You should always use SqlSessionTemplate to replace the default DefaultSqlSession implementation of MyBatis. Mixing different classes in the same application may cause data consistency problems.

SqlSessionFactory can be used as a parameter of the construction method to create a SqlSessionTemplate object.

4. Write interface and implementation classes and mapper xml

Interface:

package com.shy.dao;
import com.shy.pojo.User1;
import java.util.List;
public interface UserMapper {
    List<User1> selUser();
}

UserMapper.xml

<?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">
<!--namespace=Bind a corresponding Dao/Mapper Interface-->
<mapper namespace="com.shy.dao.UserMapper">
    <!--Query statement-->
    <select id="selUser" resultType="user1">
    select * from user1
  </select>
</mapper>

Implementation class 1:

package com.shy.dao;
import com.shy.pojo.User1;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
    //Originally, all our operations were executed using sqlSession. Now we use SqlSessionTemplate
    //sqlSession was injected into the SqlSessionTemplate attribute in the bean above
    private SqlSessionTemplate sqlSessionTemplate;
    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }
    public List<User1> selUser() {
        UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
        return mapper.selUser();
    }
}

Implementation class 2: (that is, integration implementation)

dao inherits the Support class, obtains it directly by getSqlSession(), and then injects it directly into SqlSessionFactory Compared with mode 1, there is no need to manage SqlSessionTemplate, and the Support for transactions is more friendly Traceable source code view

package com.shy.dao;
import com.shy.pojo.User1;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    public List<User1> selUser() {
        return getSqlSession().getMapper(UserMapper.class).selUser();
    }
}

4. Write ApplicationContext XML, injection bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--introduce spring-dao.xml-->
    <import resource="classpath:spring-dao.xml"/>
	
    <bean id="userMapper" class="com.shy.dao.UserMapperImpl">
        <property name="sqlSessionTemplate" ref="sqlSession"/>
    </bean>
    <bean id="userMapper2" class="com.shy.dao.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
     </bean>
</beans>

5. Write mybatis config XML, - nothing is configured by spring

<?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 Core profile-->
<configuration>
    <typeAliases>
        <package name="com.shy.pojo"/>
    </typeAliases>
</configuration>

5. Test. Play both userMapper and userMapper2

import com.shy.dao.UserMapper;
import com.shy.pojo.User1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class MyTest {
    @Test
    public void test() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
        for (User1 user1 : userMapper.selUser()) {
            System.out.println(user1);
        }
    }
}

2, Declarative transaction

1. Services:

  • Either all succeed or all fail
  • Transaction is very important in project development, which involves the consistency of data!
  • Ensure integrity and consistency

2. ACID principle of transaction

  • Atomicity
  • uniformity
  • Isolation: multiple businesses may operate the same resource to prevent data corruption
  • Persistence: once a transaction is committed, no matter what happens to the system, the result will not be affected and will be written to the memory persistently.

Transaction management in Spring

Spring defines an abstraction layer on top of different transaction management APIs, so that developers can use spring's transaction management mechanism without understanding the underlying transaction management API. Spring supports programmatic transaction management and declarative transaction management.

Programming transaction management

Embed transaction management code into business methods to control transaction submission and rollback

Disadvantages: additional transaction management code must be included in each transaction operation business logic

Declarative transaction management

In general, it is easier to use than programmatic transactions.

Separate the transaction management code from the business method and realize the transaction management in a declarative way.

Transaction management is regarded as a crosscutting concern and modularized through aop method. Spring supports declarative transaction management through the Spring AOP framework.

Transaction manager

  • No matter which transaction management strategy (programmatic or declarative) Spring uses, the transaction manager is required.
  • Spring's core transaction management abstraction encapsulates a set of technology independent methods.

example:

1. Write UserMapper interface

package com.shy.mapper;
import com.shy.pojo.User1;
import java.util.List;
public interface UserMapper {
    List<User1> selUser();
    //Add a user
    int addUser(User1 user);
    //Delete user by id
    int deleteUser(int id);
}

2. Write usermapper xml

<?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">
<!--namespace=Bind a corresponding Dao/Mapper Interface-->
<mapper namespace="com.shy.mapper.UserMapper">
    <!--Query statement-->
    <select id="selUser" resultType="user1">
        select * from user1
    </select>
    <insert id="addUser" parameterType="com.shy.pojo.User1">
        insert into user1 (id,username,password) values (#{id},#{username},#{password})
    </insert>
    <delete id="deleteUser" parameterType="int">
        delete from user1 where id = #{id}
    </delete>
</mapper>

3. Write UserMapperImpl

package com.shy.mapper;

import com.shy.pojo.User1;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
    public List<User1> selUser() {
        User1 user = new User1(5,"shysss","980");
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(5);
        return mapper.selUser();
    }

    //newly added
    public int addUser(User1 user) {
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        return mapper.addUser(user);
    }
    //delete
    public int deleteUser(int id) {
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        return mapper.deleteUser(id);
    }
}

4. Use Spring to manage transactions and write Spring Dao xml

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd"
       xmlns:tx="http://www.springframework.org/schema/tx">
    <!--DataSource:use spring Data source replacement for mybatis Configuration of  c3p0 dbcp
    Use here Spring Provided jdbc:org.springframework.jdbc.datasource-->

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/shy?useSSL=true&amp;
                useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--binding mybatis-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/shy/mapper/*.xml"/>
    </bean>

    <!--SqlSessionTemplate:That's what we use sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--Only constructor injection can be used sqlSessionFactory,Because he didn't set method-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <!--Configure transaction notifications-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--What methods are configured and what transactions are used,Configure propagation properties of transactions-->
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="search*" propagation="REQUIRED"/>
            <tx:method name="get" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--to configure aop Weaving transaction-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.shy.dao.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>

5. Write mybatis config XML, still nothing

<?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 Core profile-->
<configuration>
    <typeAliases>
        <package name="com.shy.pojo"/>
    </typeAliases>
</configuration>

6. Write ApplicationContext xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resource="spring-dao.xml"/>
    <!--to configure bean-->
    <bean id="userMapper" class="com.shy.mapper.UserMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

7. Test

import com.shy.mapper.UserMapper;
import com.shy.pojo.User1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class MyTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User1 user1 : userMapper.selUser()) {
            System.out.println(user1);
        }
    }s
    @Test
    public void test2() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper mapper = (UserMapper) context.getBean("userMapper");
        List<User1> user = mapper.selUser();
        System.out.println(user);
    }
}

spring transaction propagation features:

Transaction propagation behavior is how transactions propagate among multiple transaction methods when they call each other. spring supports seven transaction propagation behaviors:

propagation_ Requisited: if there is no transaction at present, create a new transaction. If there is already a transaction, join it. This is the most common choice.

propagation_supports: supports the current transaction. If there is no current transaction, it will be executed in a non transaction method.

propagation_mandatory: use the current transaction. If there is no current transaction, an exception will be thrown.

propagation_required_new: create a new transaction. If there is a current transaction, suspend the current transaction.

propagation_not_supported: perform operations in a non transactional manner. If there is a current transaction, suspend the current transaction.

propagation_never: execute the operation in a non transactional manner. If the current transaction exists, an exception will be thrown.

propagation_nested: if a transaction currently exists, it will be executed within a nested transaction. If there is no transaction at present, execute and propagate_ Required similar operations

The default transaction propagation behavior of Spring is PROPAGATION_REQUIRED, which is suitable for most situations

Topics: Java Mybatis Spring