MyBatis事务管理-附案例代码

发布于:2024-11-28 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、MyBatis事务管理

SqlSession对象

  • getMapper(DAO.class):获取Mapper(DAO接口的实体类)
  • 事务管理

1.1 手动提交事务

  • 手动事务管理

    • 当我们获取sqlSession对象时,就默认开启了事务;

    • 当一系列业务操作完成之后,我们需要手动提交事务 :sqlSession.commit()

    • 当操作出现异常,调用事务回滚方法:sqlSession.rollback()

@Test
    public void deleteStudent() {
        SqlSession sqlSession = null;
        try{
            //1.当我们获取sqlSession对象时,就默认开启了事务
            sqlSession = MyBatisUtil.getSqlSession();
            StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
            int i = studentDao.deleteStudent(9);
            //2.当一系列业务操作完成之后,我们需要手动提交事务
            sqlSession.commit();
        }catch (Exception e){
            //3.当操作出现异常,调用事务回滚方法
            sqlSession.rollback();
        }finally {
            sqlSession.close();
        }
    }

1.2 自动提交事务

通过SqlSessionFactory调用openSession方法获取sqlSession对象时,可以通过参数设置事务是否自动提交

如果参数设置为true,表示自动提交事务:sqlSessionFactory.openSession(true);

如果参数为空,则默认是fales,表示手动提交:sqlSessionFactory.openSession(true);

1.3 案例

数据准备

CREATE TABLE `students` (
  `stu_num` char(8) NOT NULL,
  `stu_name` varchar(20) NOT NULL,
  `stu_denger` char(2) NOT NULL,
  `stu_age` int NOT NULL,
  `stu_tel` char(11) NOT NULL,
  `stu_qq` varchar(11) DEFAULT NULL,
  `cid` int DEFAULT NULL,
  PRIMARY KEY (`stu_num`),
  KEY `FK_STUDENT_CLASS` (`cid`),
  CONSTRAINT `FK_STUDENT_CLASS` FOREIGN KEY (`cid`) REFERENCES `class` (`class_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;


INSERT INTO `db_test`.`students` (`stu_num`, `stu_name`, `stu_denger`, `stu_age`, `stu_tel`, `stu_qq`, `cid`) VALUES ('1', '蔡文姬', '女', '18', '123312312', '877877', '2');
INSERT INTO `db_test`.`students` (`stu_num`, `stu_name`, `stu_denger`, `stu_age`, `stu_tel`, `stu_qq`, `cid`) VALUES ('2', '刘禅', '男', '26', '15688887878', '332212', '1');
INSERT INTO `db_test`.`students` (`stu_num`, `stu_name`, `stu_denger`, `stu_age`, `stu_tel`, `stu_qq`, `cid`) VALUES ('3', '大乔', '女', '19', '13232322232', '4443322', '1');
INSERT INTO `db_test`.`students` (`stu_num`, `stu_name`, `stu_denger`, `stu_age`, `stu_tel`, `stu_qq`, `cid`) VALUES ('4', '小明', '男', '30', '13567899876', '8879778', '2');
INSERT INTO `db_test`.`students` (`stu_num`, `stu_name`, `stu_denger`, `stu_age`, `stu_tel`, `stu_qq`, `cid`) VALUES ('5', '鲁班大师', '男', '58', '13566656556', '9999899', '2');
INSERT INTO `db_test`.`students` (`stu_num`, `stu_name`, `stu_denger`, `stu_age`, `stu_tel`, `stu_qq`, `cid`) VALUES ('6', '墨子', '男', '38', '13788787878', '878888', NULL);
INSERT INTO `db_test`.`students` (`stu_num`, `stu_name`, `stu_denger`, `stu_age`, `stu_tel`, `stu_qq`, `cid`) VALUES ('7', '瑶', '女', '17', '136667673', '111221', NULL);
INSERT INTO `db_test`.`students` (`stu_num`, `stu_name`, `stu_denger`, `stu_age`, `stu_tel`, `stu_qq`, `cid`) VALUES ('8', '张飞', '男', '88', '13667565656', NULL, '2');

MyBatisUtil工具类

package com.feng.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @program: mybatis_project
 * @description: MyBatis工具类,提供getSqlSession和getMapper方法
 * @author: FF
 * @create: 2024-11-27 20:08
 **/
public class MyBatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    //为SqlSession加锁
    private static final ThreadLocal<SqlSession> sqlSessionlock = new ThreadLocal<>();
    static {
        InputStream inputStream = null;
        try {
            //构建sqlSession工厂
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = builder.build(inputStream);
            inputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
    
    /** 
    * @Description: 通过sqlSessionFactory,获取sqlSession对象(private不对外)
    * @Param: [isAutoCommit]
    * @return: org.apache.ibatis.session.SqlSession
    * @Author: FF
    * @Date: 2024/11/27
    */
    
    private static SqlSession getSqlSession(boolean isAutoCommit){
        SqlSession sqlSession = sqlSessionlock.get();
        if (sqlSession == null) {
            sqlSession = sqlSessionFactory.openSession(isAutoCommit);
            sqlSessionlock.set(sqlSession);
        }
        return sqlSession;
    }
    /**
    * @Description: 获取sqlSession对象,默认手动提交事务(public对外)
    * @Param: []
    * @return: org.apache.ibatis.session.SqlSession
    * @Author: FF
    * @Date: 2024/11/27
    */

    public static SqlSession getSqlSession(){
        return getSqlSession(false);
    }
    /** 
    * @Description: 提供getMapper方法,获取mapper代理对象,默认自动提交事务
    * @Param: [c]
    * @return: T
    * @Author: FF
    * @Date: 2024/11/27
    */
    
    public static <T extends Object> T getMapper(Class<T> c){
        return getSqlSession(true).getMapper(c);
    }
}

Student.java

package com.feng.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
    private String stu_num;
    private String stu_name;
    private int stu_age;
    private String stu_denger;
    private String stu_tel;
    private String stu_qq;
    private int cid;

}

StudentDao.java

package com.feng.dao;

import com.feng.pojo.Student;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface StudentDao {
    public int addStudent(Student student);
    public int deleteStudent(int id);
    public int updateStudent(Student student);
    public List<Student> selectAllStudent();
    public Student selectStudentById(String id);
    public int countStudent();
    public List<Student> selectStudentByPage(@Param("start") int start, @Param("pageSize") int pageSize);
}

StudentMapper.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">

<!--mapper相当与DAO接口的实现类,namespace属性要指定实现DAO接口的全限定名-->
<mapper namespace="com.feng.dao.StudentDao">
    <resultMap id="studentMap" type="com.feng.pojo.Student">
        <id column="stu_num" property="stu_num"></id>
        <result column="stu_name" property="stu_name"></result>
        <result column="stu_age" property="stu_age"></result>
        <result column="stu_denger" property="stu_denger"></result>
        <result column="stu_tel" property="stu_tel"></result>
        <result column="stu_qq" property="stu_qq"></result>
        <result column="cid" property="cid"></result>
    </resultMap>
    <insert id="addStudent" parameterType="com.feng.pojo.Student" useGeneratedKeys="true" keyProperty="stu_num">
        insert into students(stu_num,stu_name,stu_age,stu_denger,stu_tel,stu_qq,cid)
        values (#{stu_num},#{stu_name},#{stu_age},#{stu_denger},#{stu_tel},#{stu_qq},#{cid})
    </insert>
    <delete id="deleteStudent">
        delete from students where stu_num = #{stu_num}
    </delete>
    <update id="updateStudent">
        update students set
            stu_num = #{stu_num},stu_name=#{stu_name},stu_age=#{stu_age},stu_denger=#{stu_denger},
            stu_tel=#{stu_tel},stu_qq=#{stu_qq},cid=#{cid}
        where
            stu_num = #{stu_num}
    </update>
    <select id="selectAllStudent" resultType="com.feng.pojo.Student" resultMap="studentMap">
        select * from students
    </select>
    <select id="selectStudentById" resultMap="studentMap">
        select * from students where stu_num = #{stu_num}
    </select>
    <select id="countStudent" resultType="int">
        select count(1) from students;
    </select>
    <select id="selectStudentByPage" resultMap="studentMap">
        select * from students limit #{start},#{pageSize}
    </select>
</mapper>

mybatis-config.xml

<?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>
    <!--配置数据库连接信息-->
    <environments default="mysql">
        <environment id="mysql">
            <!--用于配置数据库管理方式-->
            <transactionManager type="JDBC">

            </transactionManager>
            <!--配置数据库连接方式-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/db_test?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--需要将映射文件添加到主文件中-->
    <mappers>
        <mapper resource="mappers/StudentMapper.xml"></mapper>
    </mappers>
</configuration>

测试类

package com.feng.dao;

import com.feng.pojo.Student;
import com.feng.utils.MyBatisUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import static org.junit.Assert.*;

public class StudentDaoTest {

    /**
    * @Description: 添加方法测试,未使用MyBatisUtils工具类,全部手写
    * @Param: []
    * @return: void
    * @Author: FF
    * @Date: 2024/11/27
    */

    @org.junit.Test
    public void addStudent() throws IOException {
        //加载mybatis配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //构建session工厂
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //会话工厂
        SqlSessionFactory factory = sqlSessionFactoryBuilder.build(inputStream);
        //会话(连接)
        SqlSession sqlSession = factory.openSession();
        //通过会话,获取dao对象
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        //测试dao方法
        Student student = new Student();
        student.setStu_num("9");
        student.setStu_name("太乙真人");
        student.setStu_age(88);
        student.setStu_denger("男");
        student.setStu_tel("123312312");
        student.setStu_qq("877877");
        student.setCid(2);

        int i = studentDao.addStudent(student);
        //手动提交事务
        sqlSession.commit();
        //关闭会话
        sqlSession.close();
        //关闭流
        inputStream.close();
        System.out.println(i);

    }
/** 
* @Description: 删除方法测试,调用MyBatisUtil.getSqlSession()方法,默认手动提交事务
* @Param: []
* @return: void
* @Author: FF
* @Date: 2024/11/27
*/

    @Test
    public void deleteStudent() {
        SqlSession sqlSession = null;
        try{
            //1.当我们获取sqlSession对象时,就默认开启了事务(getSqlSession()方法,默认的事务提交方式是手动提交)
            sqlSession = MyBatisUtil.getSqlSession();
            StudentDao studentDao = MyBatisUtil.getMapper(StudentDao.class);
            int i = studentDao.deleteStudent(9);
            //2.当一系列业务操作完成之后,我们需要手动提交事务
            sqlSession.commit();
            System.out.println(i);
        }catch (Exception e){
            //3.当操作出现异常,调用事务回滚方法
            sqlSession.rollback();
        }
    }
/** 
* @Description: 修改方法测试,调用MyBatisUtil.getMapper()方法,默认自动提交事务
* @Param: []
* @return: void
* @Author: FF
* @Date: 2024/11/27
*/

    @Test
    public void updateStudent() throws IOException {
        //MyBatisUtil.getMapper(StudentDao.class)方法默认的是自动提交事务
        StudentDao studentDao = MyBatisUtil.getMapper(StudentDao.class);
        Student student = new Student();
        student.setStu_num("1");
        student.setStu_name("蔡文姬");
        student.setStu_age(18);
        student.setStu_denger("女");
        student.setStu_tel("123312312");
        student.setStu_qq("877877");
        student.setCid(2);
        int i = studentDao.updateStudent(student);

        assertEquals(1, 1);

    }

    @Test
    public void selectAllStudent() {
        StudentDao studentDao = MyBatisUtil.getMapper(StudentDao.class);
        List<Student> students = studentDao.selectAllStudent();
        assertNotNull(students);
        System.out.println(students.size());
        for (Student student : students) {
            System.out.println(student);
        }
    }

    @Test
    public void selectStudentById() throws IOException {

        StudentDao studentDao = MyBatisUtil.getMapper(StudentDao.class);
        Student student = studentDao.selectStudentById("3");
        System.out.println(student);
    }

    @Test
    public void countStudent() throws IOException {
        StudentDao studentDao = MyBatisUtil.getMapper(StudentDao.class);
        int count = studentDao.countStudent();
        System.out.println(count);
    }

    @Test
    public void selectStudentByPage() {
        StudentDao mapperer = MyBatisUtil.getMapper(StudentDao.class);
        List<Student> students = mapperer.selectStudentByPage(0,5);
        assertNotNull(students);
        System.out.println(students.size());
        for (Student student : students) {
            System.out.println(student);
        }
    }
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.feng</groupId>
  <artifactId>mybatis_project</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>mybatis_project Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!-- mysql-connector-j -->
    <dependency>
      <groupId>com.mysql</groupId>
      <artifactId>mysql-connector-j</artifactId>
      <version>8.2.0</version>
    </dependency>
    <!-- mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>
    <!-- lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.30</version>
      <scope>provided</scope>
    </dependency>

  </dependencies>
  <build>
    <finalName>mybatis_project</finalName>
  </build>
</project>

工程目录结构
在这里插入图片描述