Przeglądaj źródła

fix:https://github.com/baomidou/mybatis-plus/issues/373

聂秋荣 7 lat temu
rodzic
commit
b053e33ad4

+ 2 - 0
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/test/h2/H2ARTest.java

@@ -18,6 +18,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
 import com.baomidou.mybatisplus.test.h2.base.AbstractH2UserTest;
 import com.baomidou.mybatisplus.test.h2.entity.persistent.H2UserIntVersionAR;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * <p>
@@ -42,6 +43,7 @@ public class H2ARTest extends AbstractH2UserTest {
     }
 
     @Test
+    @Transactional
     public void testAROptimisticLock() {
         H2UserIntVersionAR user = new H2UserIntVersionAR();
         user = user.selectById(105);

+ 6 - 0
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/test/h2/config/MybatisPlusConfig.java

@@ -2,6 +2,7 @@ package com.baomidou.mybatisplus.test.h2.config;
 
 import javax.sql.DataSource;
 
+import com.baomidou.mybatisplus.MybatisSqlSessionTemplate;
 import org.apache.ibatis.plugin.Interceptor;
 import org.apache.ibatis.session.SqlSessionFactory;
 import org.apache.ibatis.type.JdbcType;
@@ -64,4 +65,9 @@ public class MybatisPlusConfig {
         conf.setIdType(2);
         return conf;
     }
+    
+    @Bean
+    public MybatisSqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory){
+        return new MybatisSqlSessionTemplate(sqlSessionFactory);
+    }
 }

+ 26 - 6
mybatis-plus-support/src/main/java/com/baomidou/mybatisplus/MybatisSqlSessionTemplate.java

@@ -16,6 +16,10 @@
 package com.baomidou.mybatisplus;
 
 import static java.lang.reflect.Proxy.newProxyInstance;
+import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;
+import static org.mybatis.spring.SqlSessionUtils.closeSqlSession;
+import static org.mybatis.spring.SqlSessionUtils.getSqlSession;
+import static org.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional;
 
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
@@ -24,6 +28,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.ibatis.cursor.Cursor;
+import org.apache.ibatis.exceptions.PersistenceException;
 import org.apache.ibatis.executor.BatchResult;
 import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.session.ExecutorType;
@@ -36,7 +41,6 @@ import org.springframework.beans.factory.DisposableBean;
 import org.springframework.dao.support.PersistenceExceptionTranslator;
 import org.springframework.util.Assert;
 
-import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
 
 /**
  * Copy SqlSessionTemplate
@@ -395,17 +399,33 @@ public class MybatisSqlSessionTemplate implements SqlSession, DisposableBean {
 
         @Override
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-            SqlSession sqlSession = MybatisSqlSessionTemplate.this.sqlSessionFactory
-                .openSession(MybatisSqlSessionTemplate.this.executorType);
+            SqlSession sqlSession = getSqlSession(
+                MybatisSqlSessionTemplate.this.sqlSessionFactory,
+                MybatisSqlSessionTemplate.this.executorType,
+                MybatisSqlSessionTemplate.this.exceptionTranslator);
             try {
                 Object result = method.invoke(sqlSession, args);
-                sqlSession.commit(true);
+                if (!isSqlSessionTransactional(sqlSession, MybatisSqlSessionTemplate.this.sqlSessionFactory)) {
+                    // force commit even on non-dirty sessions because some databases require
+                    // a commit/rollback before calling close()
+                    sqlSession.commit(true);
+                }
                 return result;
             } catch (Throwable t) {
-                throw new MybatisPlusException(t);
+                Throwable unwrapped = unwrapThrowable(t);
+                if (MybatisSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
+                    // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
+                    closeSqlSession(sqlSession, MybatisSqlSessionTemplate.this.sqlSessionFactory);
+                    sqlSession = null;
+                    Throwable translated = MybatisSqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
+                    if (translated != null) {
+                        unwrapped = translated;
+                    }
+                }
+                throw unwrapped;
             } finally {
                 if (sqlSession != null) {
-                    sqlSession.close();
+                    closeSqlSession(sqlSession, MybatisSqlSessionTemplate.this.sqlSessionFactory);
                 }
             }
         }

+ 14 - 38
mybatis-plus-support/src/main/java/com/baomidou/mybatisplus/activerecord/Model.java

@@ -53,9 +53,7 @@ public abstract class Model<T extends Model> implements Serializable {
      */
     @Transactional
     public boolean insert() {
-        try (SqlSession sqlSession = sqlSession()) {
-            return SqlHelper.retBool(sqlSession.insert(sqlStatement(SqlMethod.INSERT_ONE), this));
-        }
+        return SqlHelper.retBool(sqlSession().insert(sqlStatement(SqlMethod.INSERT_ONE), this));
     }
 
     /**
@@ -65,9 +63,7 @@ public abstract class Model<T extends Model> implements Serializable {
      */
     @Transactional
     public boolean insertAllColumn() {
-        try (SqlSession sqlSession = sqlSession()) {
-            return SqlHelper.retBool(sqlSession.insert(sqlStatement(SqlMethod.INSERT_ONE_ALL_COLUMN), this));
-        }
+        return SqlHelper.retBool(sqlSession().insert(sqlStatement(SqlMethod.INSERT_ONE_ALL_COLUMN), this));
     }
 
     /**
@@ -98,9 +94,7 @@ public abstract class Model<T extends Model> implements Serializable {
      */
     @Transactional
     public boolean deleteById(Serializable id) {
-        try (SqlSession sqlSession = sqlSession()) {
-            return SqlHelper.delBool(sqlSession.delete(sqlStatement(SqlMethod.DELETE_BY_ID), id));
-        }
+        return SqlHelper.delBool(sqlSession().delete(sqlStatement(SqlMethod.DELETE_BY_ID), id));
     }
 
     /**
@@ -144,9 +138,7 @@ public abstract class Model<T extends Model> implements Serializable {
     public boolean delete(Wrapper wrapper) {
         Map<String, Object> map = new HashMap<>();
         map.put("ew", wrapper);
-        try (SqlSession sqlSession = sqlSession()){
-            return SqlHelper.delBool(sqlSession.delete(sqlStatement(SqlMethod.DELETE), map));
-        }
+        return SqlHelper.delBool(sqlSession().delete(sqlStatement(SqlMethod.DELETE), map));
     }
 
     /**
@@ -162,9 +154,7 @@ public abstract class Model<T extends Model> implements Serializable {
         // updateById
         Map<String, Object> map = new HashMap<>();
         map.put("et", this);
-        try (SqlSession sqlSession = sqlSession()){
-            return SqlHelper.retBool(sqlSession.update(sqlStatement(SqlMethod.UPDATE_BY_ID), map));
-        }
+        return SqlHelper.retBool(sqlSession().update(sqlStatement(SqlMethod.UPDATE_BY_ID), map));
     }
 
     /**
@@ -180,9 +170,7 @@ public abstract class Model<T extends Model> implements Serializable {
         // updateAllColumnById
         Map<String, Object> map = new HashMap<>();
         map.put("et", this);
-        try (SqlSession sqlSession = sqlSession()){
-            return SqlHelper.retBool(sqlSession.update(sqlStatement(SqlMethod.UPDATE_ALL_COLUMN_BY_ID), map));
-        }
+        return SqlHelper.retBool(sqlSession().update(sqlStatement(SqlMethod.UPDATE_ALL_COLUMN_BY_ID), map));
     }
 
     /**
@@ -214,9 +202,7 @@ public abstract class Model<T extends Model> implements Serializable {
         map.put("et", this);
         map.put("ew", wrapper);
         // update
-        try (SqlSession sqlSession = sqlSession()){
-            return SqlHelper.retBool(sqlSession.update(sqlStatement(SqlMethod.UPDATE), map));
-        }
+        return SqlHelper.retBool(sqlSession().update(sqlStatement(SqlMethod.UPDATE), map));
     }
 
     /**
@@ -227,9 +213,7 @@ public abstract class Model<T extends Model> implements Serializable {
      * @return
      */
     public List<T> selectAll() {
-        try (SqlSession sqlSession = sqlSession()){
-            return sqlSession.selectList(sqlStatement(SqlMethod.SELECT_LIST));
-        }
+        return sqlSession().selectList(sqlStatement(SqlMethod.SELECT_LIST));
     }
 
     /**
@@ -241,9 +225,7 @@ public abstract class Model<T extends Model> implements Serializable {
      * @return
      */
     public T selectById(Serializable id) {
-        try (SqlSession sqlSession = sqlSession()){
-            return sqlSession.selectOne(sqlStatement(SqlMethod.SELECT_BY_ID), id);
-        }
+        return sqlSession().selectOne(sqlStatement(SqlMethod.SELECT_BY_ID), id);
     }
 
     /**
@@ -272,9 +254,7 @@ public abstract class Model<T extends Model> implements Serializable {
     public List<T> selectList(Wrapper wrapper) {
         Map<String, Object> map = new HashMap<>();
         map.put("ew", wrapper);
-        try (SqlSession sqlSession = sqlSession()){
-            return sqlSession.selectList(sqlStatement(SqlMethod.SELECT_LIST), map);
-        }
+        return sqlSession().selectList(sqlStatement(SqlMethod.SELECT_LIST), map);
     }
 
     /**
@@ -328,11 +308,9 @@ public abstract class Model<T extends Model> implements Serializable {
         Map<String, Object> map = new HashMap<>();
         wrapper = (Wrapper<T>) SqlHelper.fillWrapper(page, wrapper);
         map.put("ew", wrapper);
-        try (SqlSession sqlSession = sqlSession()){
-            List<T> tl = sqlSession.selectList(sqlStatement(SqlMethod.SELECT_PAGE), map, page);
-            page.setRecords(tl);
-            return page;
-        }
+        List<T> tl = sqlSession().selectList(sqlStatement(SqlMethod.SELECT_PAGE), map, page);
+        page.setRecords(tl);
+        return page;
     }
 
     /**
@@ -374,9 +352,7 @@ public abstract class Model<T extends Model> implements Serializable {
     public int selectCount(Wrapper wrapper) {
         Map<String, Object> map = new HashMap<>();
         map.put("ew", wrapper);
-        try (SqlSession sqlSession = sqlSession()){
-            return SqlHelper.retCount(sqlSession.<Integer>selectOne(sqlStatement(SqlMethod.SELECT_COUNT), map));
-        }
+        return SqlHelper.retCount(sqlSession().<Integer>selectOne(sqlStatement(SqlMethod.SELECT_COUNT), map));
     }
 
     /**

+ 10 - 1
mybatis-plus-support/src/main/java/com/baomidou/mybatisplus/entity/GlobalConfiguration.java

@@ -104,6 +104,10 @@ public class GlobalConfiguration implements Serializable {
      * 缓存已注入CRUD的Mapper信息
      */
     private Set<String> mapperRegistryCache = new ConcurrentSkipListSet<>();
+    /**
+     * 单例重用SqlSession
+     */
+    private SqlSession sqlSession;
     /**
      * 缓存 Sql 解析初始化
      */
@@ -224,6 +228,7 @@ public class GlobalConfiguration implements Serializable {
 
     public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
         this.sqlSessionFactory = sqlSessionFactory;
+        this.sqlSession = new MybatisSqlSessionTemplate(sqlSessionFactory);
     }
 
     public boolean isCapitalMode() {
@@ -258,7 +263,11 @@ public class GlobalConfiguration implements Serializable {
             SqlReservedWords.RESERVED_WORDS.addAll(StringUtils.splitWorker(sqlKeywords.toUpperCase(), ",", -1, false));
         }
     }
-
+    
+    public SqlSession getSqlSession() {
+        return sqlSession;
+    }
+    
     public boolean isSqlParserCache() {
         return sqlParserCache;
     }

+ 24 - 15
mybatis-plus-support/src/main/java/com/baomidou/mybatisplus/mapper/SqlHelper.java

@@ -19,8 +19,10 @@ import java.util.List;
 
 import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.session.ExecutorType;
 import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
 
 import com.baomidou.mybatisplus.entity.TableInfo;
 import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
@@ -29,6 +31,7 @@ import com.baomidou.mybatisplus.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.toolkit.GlobalConfigUtils;
 import com.baomidou.mybatisplus.toolkit.MapUtils;
 import com.baomidou.mybatisplus.toolkit.TableInfoHelper;
+import org.mybatis.spring.SqlSessionUtils;
 
 /**
  * <p>
@@ -44,28 +47,34 @@ public class SqlHelper {
 
     /**
      * <p>
-     * 获取Session 默认自动提交
+     * 批量操作 SqlSession
      * </p>
-     * <p>
-     * 特别说明:这里获取SqlSession时这里虽然设置了自动提交但是如果事务托管了的话 是不起作用的 切记!!
-     * <p/>
      *
+     * @param clazz 实体类
      * @return SqlSession
      */
-    public static SqlSession sqlSession(Class<?> clazz) {
-        return sqlSession(clazz, true);
+    public static SqlSession sqlSessionBatch(Class<?> clazz) {
+        return GlobalConfigUtils.currentSessionFactory(clazz).openSession(ExecutorType.BATCH);
     }
-
+    
     /**
      * <p>
-     * 批量操作 SqlSession
+     * 获取sqlSession
      * </p>
      *
-     * @param clazz 实体
-     * @return SqlSession
+     * @param clazz 对象
+     * @return
      */
-    public static SqlSession sqlSessionBatch(Class<?> clazz) {
-        return GlobalConfigUtils.currentSessionFactory(clazz).openSession(ExecutorType.BATCH);
+    private static SqlSession getSqlSession(Class<?> clazz) {
+        SqlSession session = null;
+        try {
+            SqlSessionFactory sqlSessionFactory = GlobalConfigUtils.currentSessionFactory(clazz);
+            Configuration configuration = sqlSessionFactory.getConfiguration();
+            session = GlobalConfigUtils.getGlobalConfig(configuration).getSqlSession();
+        } catch (Exception e) {
+            // ignored
+        }
+        return session;
     }
 
     /**
@@ -74,11 +83,11 @@ public class SqlHelper {
      * </p>
      *
      * @param clazz      实体类
-     * @param autoCommit true自动提交false则相反
      * @return SqlSession
      */
-    public static SqlSession sqlSession(Class<?> clazz, boolean autoCommit) {
-        return GlobalConfigUtils.currentSessionFactory(clazz).openSession(autoCommit);
+    public static SqlSession sqlSession(Class<?> clazz) {
+        SqlSession sqlSession = getSqlSession(clazz);
+        return sqlSession !=null ? sqlSession:SqlSessionUtils.getSqlSession(GlobalConfigUtils.currentSessionFactory(clazz));
     }
 
     /**

+ 12 - 23
mybatis-plus-support/src/main/java/com/baomidou/mybatisplus/mapper/SqlRunner.java

@@ -19,6 +19,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import com.baomidou.mybatisplus.MybatisSqlSessionTemplate;
 import org.apache.ibatis.session.SqlSession;
 import org.apache.ibatis.session.SqlSessionFactory;
 import org.springframework.transaction.annotation.Transactional;
@@ -49,6 +50,7 @@ public class SqlRunner {
     // 默认FACTORY
     public static SqlSessionFactory FACTORY;
     private SqlSessionFactory sqlSessionFactory;
+    private static SqlSession SQL_SESSION;
 
     private Class<?> clazz;
 
@@ -71,6 +73,7 @@ public class SqlRunner {
         // 初始化的静态变量 还是有前后加载的问题 该判断只会执行一次
         if (DEFAULT.sqlSessionFactory == null) {
             DEFAULT.sqlSessionFactory = FACTORY;
+            SQL_SESSION = new MybatisSqlSessionTemplate(FACTORY);
         }
         return DEFAULT;
     }
@@ -89,16 +92,12 @@ public class SqlRunner {
 
     @Transactional
     public boolean insert(String sql, Object... args) {
-        try (SqlSession session = sqlSession()) {
-            return SqlHelper.retBool(session.insert(INSERT, sqlMap(sql, args)));
-        }
+        return SqlHelper.retBool(sqlSession().insert(INSERT, sqlMap(sql, args)));
     }
 
     @Transactional
     public boolean delete(String sql, Object... args) {
-        try (SqlSession session = sqlSession()) {
-            return SqlHelper.retBool(session.delete(DELETE, sqlMap(sql, args)));
-        }
+        return SqlHelper.retBool(sqlSession().delete(DELETE, sqlMap(sql, args)));
     }
 
     /**
@@ -116,9 +115,7 @@ public class SqlRunner {
 
     @Transactional
     public boolean update(String sql, Object... args) {
-        try (SqlSession session = sqlSession()) {
-            return SqlHelper.retBool(session.update(UPDATE, sqlMap(sql, args)));
-        }
+        return SqlHelper.retBool(sqlSession().update(UPDATE, sqlMap(sql, args)));
     }
 
     /**
@@ -130,9 +127,7 @@ public class SqlRunner {
      * @return
      */
     public List<Map<String, Object>> selectList(String sql, Object... args) {
-        try (SqlSession session = sqlSession()) {
-            return session.selectList(SELECT_LIST, sqlMap(sql, args));
-        }
+        return sqlSession().selectList(SELECT_LIST, sqlMap(sql, args));
     }
 
     /**
@@ -144,9 +139,7 @@ public class SqlRunner {
      * @return
      */
     public List<Object> selectObjs(String sql, Object... args) {
-        try (SqlSession session = sqlSession()) {
-            return session.selectList(SELECT_OBJS, sqlMap(sql, args));
-        }
+        return sqlSession().selectList(SELECT_OBJS, sqlMap(sql, args));
     }
 
     /**
@@ -162,9 +155,7 @@ public class SqlRunner {
     }
 
     public int selectCount(String sql, Object... args) {
-        try (SqlSession session = sqlSession()) {
-            return SqlHelper.retCount(session.<Integer>selectOne(COUNT, sqlMap(sql, args)));
-        }
+        return SqlHelper.retCount(sqlSession().<Integer>selectOne(COUNT, sqlMap(sql, args)));
     }
 
     public Map<String, Object> selectOne(String sql, Object... args) {
@@ -176,10 +167,8 @@ public class SqlRunner {
         if (null == page) {
             return null;
         }
-        try (SqlSession session = sqlSession()) {
-            page.setRecords(session.selectList(SELECT_LIST, sqlMap(sql, args), page));
-            return page;
-        }
+        page.setRecords(sqlSession().selectList(SELECT_LIST, sqlMap(sql, args), page));
+        return page;
     }
 
     /**
@@ -188,7 +177,7 @@ public class SqlRunner {
      * <p/>
      */
     private SqlSession sqlSession() {
-        return (clazz != null) ? SqlHelper.sqlSession(clazz) : FACTORY.openSession(true);
+        return (clazz != null) ? SqlHelper.sqlSession(clazz) : SQL_SESSION;
     }
 
 }