• 封装MybatisUtils解决线程安全与事务问题


    Mybatis入门_做测试的喵酱的博客-CSDN博客

    一、解决问题

    MybatisUtils,封装获取mybatis的sqlSession 的方法。

    需要解决2个问题:

    1.1、线程安全问题

    需要为单例模式。一个线程中,get到的sqlSession是同一个。

    1.2、事务安全问题

    (我对事物的理解,就是将几个行为,捆绑在一起,组合成一个事务。

    在真正执行事务之前,会先预演一遍。

    预演时,只有当所有的行为都执行成功时,才会去执行这个事务。保证每一个步骤都执行成功。

    当其中一个行为执行失败,则整个事务执行失败。就不会去真正的执行这个失败的事物,每一个步骤,都没有真正的去执行。

    举例:

    A 给B 转账100元。数据库一共有2个行为,行为1是A扣款100元。行为2是B的余额中增加100元。

    我们必须保证这两个行为同时成功或者同时失败,如果只有其中一个行为成功,另一个行为失败,都会造成事故。

    所以我们将A给B转账的这个情景,这2个行为组成一个事务。(线程1上的一个事务)

    A与B转账的同时(线程1),C也在给D转账(线程2),C与D 的行为组成一个事务,A与B的行为组成一个事务。

    每个线程需要有自己的单独事务,则每个线程需要有自己单独sqlSession。

    1.3 我们想要的最终效果

    每个线程上的sqlSession是单例的。

    但是线程与线程之间,每个线程都有一个属于自己线程的sqlSession。

    我们这里通过内部静态类与ThreadLocal实现的。

    二、代码

    2.1 工具类MyBatisUtils

    MyBatisUtils

    1. package utils;
    2. import org.apache.ibatis.io.Resources;
    3. import org.apache.ibatis.session.SqlSession;
    4. import org.apache.ibatis.session.SqlSessionFactory;
    5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    6. import java.io.IOException;
    7. import java.io.InputStream;
    8. public class MyBatisUtils {
    9. private static SqlSessionFactory sqlSessionFactory;
    10. // ThreadLocal,每个线程,都使用各自的一个SqlSession
    11. private static ThreadLocal threadLocal = new ThreadLocal<>();
    12. static {
    13. InputStream in = null;
    14. try {
    15. in = Resources.getResourceAsStream("mybatis-config.xml");
    16. } catch (IOException e){
    17. e.printStackTrace();
    18. }
    19. sqlSessionFactory = new SqlSessionFactoryBuilder().build(in,"test");
    20. }
    21. public static SqlSession getSqlSession(){
    22. SqlSession sqlSession = threadLocal.get();
    23. if(sqlSession==null){
    24. sqlSession= sqlSessionFactory.openSession(false);
    25. threadLocal.set(sqlSession);
    26. }
    27. return sqlSession;
    28. }
    29. public static void commit(){
    30. SqlSession sqlSession = threadLocal.get();
    31. if (sqlSession != null){
    32. sqlSession.commit();
    33. }
    34. }
    35. public static void closeSqlSession(){
    36. SqlSession sqlSession = threadLocal.get();
    37. if (sqlSession != null){
    38. sqlSession.close();
    39. threadLocal.remove();
    40. }
    41. }
    42. }

    注意:

    1、sqlSession= sqlSessionFactory.openSession(false);

    false 是不自动进行commit的,需要我们手动的进行commit。(事务的需要,)

    2、ThreadLocal实现了每个线程有一个属于自己的 sqlSession

    2.2 方法调用

    1. package main;
    2. import com.google.common.collect.Lists;
    3. import entity.MyStudent;
    4. import mapper.MyStudentMapper;
    5. import org.apache.ibatis.io.Resources;
    6. import org.apache.ibatis.session.SqlSession;
    7. import org.apache.ibatis.session.SqlSessionFactory;
    8. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    9. import utils.MyBatisUtils;
    10. import java.io.IOException;
    11. import java.io.InputStream;
    12. import java.util.ArrayList;
    13. import java.util.List;
    14. public class App3 {
    15. public static void main(String[] args) throws IOException {
    16. SqlSession sqlSession = MyBatisUtils.getSqlSession();
    17. // 得到MyStudent表的mapper
    18. MyStudentMapper myStudentMapper = sqlSession.getMapper(MyStudentMapper.class);
    19. // 调用mapper的方法
    20. List all = myStudentMapper.findAll();
    21. System.out.println("all = " + all);
    22. MyBatisUtils.closeSqlSession();
    23. }
    24. }

    2.3 证明线程内是单例的,多个线程间是不单例的。

    1. package main;
    2. import entity.MyStudent;
    3. import mapper.MyStudentMapper;
    4. import org.apache.ibatis.session.SqlSession;
    5. import utils.MyBatisUtils;
    6. import java.io.IOException;
    7. import java.util.List;
    8. public class App4 {
    9. public static void main(String[] args) throws IOException {
    10. for (int i=0;i<3;i++){
    11. new Thread(){
    12. @Override
    13. public void run() {
    14. SqlSession sqlSession = MyBatisUtils.getSqlSession();
    15. // 得到MyStudent表的mapper
    16. MyStudentMapper myStudentMapper = sqlSession.getMapper(MyStudentMapper.class);
    17. // 调用mapper的方法
    18. List all = myStudentMapper.findAll();
    19. System.out.println("all = " + all);
    20. System.out.println(this.getId()+"sqlSession = " + sqlSession);
    21. SqlSession sqlSession2 = MyBatisUtils.getSqlSession();
    22. System.out.println(this.getId()+"sqlSession2 = " + sqlSession2);
    23. MyBatisUtils.closeSqlSession();
    24. }
    25. }.start();
    26. }
    27. }
    28. }

    打印结果:

    1. /Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=61163:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/lib/tools.jar:/Users/zhaohui/IdeaProjects/MyTest/YourBatiesStudy/target/classes:/Users/zhaohui/.m2/repository/org/mybatis/mybatis/3.5.6/mybatis-3.5.6.jar:/Users/zhaohui/.m2/repository/mysql/mysql-connector-java/8.0.20/mysql-connector-java-8.0.20.jar:/Users/zhaohui/.m2/repository/org/apache/commons/commons-lang3/3.9/commons-lang3-3.9.jar:/Users/zhaohui/.m2/repository/com/google/guava/guava/30.1.1-jre/guava-30.1.1-jre.jar:/Users/zhaohui/.m2/repository/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar:/Users/zhaohui/.m2/repository/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:/Users/zhaohui/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/zhaohui/.m2/repository/org/checkerframework/checker-qual/3.8.0/checker-qual-3.8.0.jar:/Users/zhaohui/.m2/repository/com/google/errorprone/error_prone_annotations/2.5.1/error_prone_annotations-2.5.1.jar:/Users/zhaohui/.m2/repository/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar:/Users/zhaohui/.m2/repository/org/projectlombok/lombok/1.18.18/lombok-1.18.18.jar main.App4
    2. all = [MyStudent(id=201215121, name=李勇, age=20), MyStudent(id=201215122, name=刘晨, age=19), MyStudent(id=201215123, name=王敏, age=18), MyStudent(id=201215127, name=张三, age=19), MyStudent(id=201215128, name=张三, age=19), MyStudent(id=201215129, name=张三, age=19), MyStudent(id=201215130, name=张三, age=19), MyStudent(id=201215131, name=张三, age=19), MyStudent(id=201215132, name=张三, age=19), MyStudent(id=201215133, name=张三, age=19), MyStudent(id=201215134, name=张三三, age=19), MyStudent(id=201215135, name=李思思, age=19), MyStudent(id=201215136, name=张三, age=19), MyStudent(id=201215139, name=张三, age=19), MyStudent(id=201215140, name=张三三, age=19), MyStudent(id=201215141, name=李思思, age=19), MyStudent(id=201215142, name=张三, age=19), MyStudent(id=201215143, name=张三三, age=19), MyStudent(id=201215144, name=李思思, age=19)]
    3. 13sqlSession = org.apache.ibatis.session.defaults.DefaultSqlSession@1e57f15
    4. 13sqlSession2 = org.apache.ibatis.session.defaults.DefaultSqlSession@1e57f15
    5. all = [MyStudent(id=201215121, name=李勇, age=20), MyStudent(id=201215122, name=刘晨, age=19), MyStudent(id=201215123, name=王敏, age=18), MyStudent(id=201215127, name=张三, age=19), MyStudent(id=201215128, name=张三, age=19), MyStudent(id=201215129, name=张三, age=19), MyStudent(id=201215130, name=张三, age=19), MyStudent(id=201215131, name=张三, age=19), MyStudent(id=201215132, name=张三, age=19), MyStudent(id=201215133, name=张三, age=19), MyStudent(id=201215134, name=张三三, age=19), MyStudent(id=201215135, name=李思思, age=19), MyStudent(id=201215136, name=张三, age=19), MyStudent(id=201215139, name=张三, age=19), MyStudent(id=201215140, name=张三三, age=19), MyStudent(id=201215141, name=李思思, age=19), MyStudent(id=201215142, name=张三, age=19), MyStudent(id=201215143, name=张三三, age=19), MyStudent(id=201215144, name=李思思, age=19)]
    6. 11sqlSession = org.apache.ibatis.session.defaults.DefaultSqlSession@2f73d49b
    7. 11sqlSession2 = org.apache.ibatis.session.defaults.DefaultSqlSession@2f73d49b
    8. all = [MyStudent(id=201215121, name=李勇, age=20), MyStudent(id=201215122, name=刘晨, age=19), MyStudent(id=201215123, name=王敏, age=18), MyStudent(id=201215127, name=张三, age=19), MyStudent(id=201215128, name=张三, age=19), MyStudent(id=201215129, name=张三, age=19), MyStudent(id=201215130, name=张三, age=19), MyStudent(id=201215131, name=张三, age=19), MyStudent(id=201215132, name=张三, age=19), MyStudent(id=201215133, name=张三, age=19), MyStudent(id=201215134, name=张三三, age=19), MyStudent(id=201215135, name=李思思, age=19), MyStudent(id=201215136, name=张三, age=19), MyStudent(id=201215139, name=张三, age=19), MyStudent(id=201215140, name=张三三, age=19), MyStudent(id=201215141, name=李思思, age=19), MyStudent(id=201215142, name=张三, age=19), MyStudent(id=201215143, name=张三三, age=19), MyStudent(id=201215144, name=李思思, age=19)]
    9. 12sqlSession = org.apache.ibatis.session.defaults.DefaultSqlSession@4596a997
    10. 12sqlSession2 = org.apache.ibatis.session.defaults.DefaultSqlSession@4596a997
    11. Process finished with exit code 0

    同一个线程内的多个 sqlSession 的物理地址是一样的,

    多个线程间, sqlSession 的物理地址是不一样的。

     
    

  • 相关阅读:
    【TS04——接口的多态——泛型接口】
    修改一个MD5的VB源码,使用它支持UTF8编码
    eyb:JWT介绍
    go-05-常量
    MySQL 日志管理
    Pycharm 2023 设置远程调试
    320力扣周赛总结
    操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities)
    合伙保密协议
    最详细STM32,cubeMX串口发送,接收数据
  • 原文地址:https://blog.csdn.net/qq_39208536/article/details/128191439