最近学习mybatis时发现一个问题,从threadlocal里取出的sqlsession是null 是null

qq_38841290 2021-01-18 10:39:23
SqlSessionUtil工具类
public class SqlsessionUtil {
private static SqlSessionFactory sqlSessionFactory;
private static ThreadLocal<SqlSession> threadLocal;
//类加载时初始化sqlSessionFactory
static {
try {
InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
threadLocal=new ThreadLocal<SqlSession>();
}

/**
* 得到sqlsession
* @return
*/
public static SqlSession getSqlCurrentSqlsession(){
SqlSession sqlSession=threadLocal.get();
if (sqlSession==null){
sqlSession=sqlSessionFactory.openSession();
threadLocal.set(sqlSession);
}
return sqlSession;
}

/**
* 回滚
* @param sqlSession
*/
public static void rollBack(SqlSession sqlSession){

if (sqlSession!=null){
sqlSession.rollback();
}
}

/**
*释放资源
* @param sqlSession
*/
public static void close(SqlSession sqlSession){
if (sqlSession!=null){
sqlSession.close();
threadLocal.remove();
}

}


}


事务处理器TransactionHandler

public class TransactionHandler implements InvocationHandler {
//目标对象
private Object target;
//构造器

public TransactionHandler(Object target) {
this.target = target;
}
//得到代理对象
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession=null;
Object invoke=null;
try{
//手动提交事务
sqlSession = SqlsessionUtil.getSqlCurrentSqlsession();
//dowork
invoke=method.invoke(target,args);
//提交事务
sqlSession.commit();
}catch (Exception e){
//回滚
SqlsessionUtil.rollBack(sqlSession);
e.printStackTrace();

}finally {
SqlsessionUtil.close(sqlSession);
}

return invoke;
}


}


UserDao 和UserDaoImpl
public interface UserDao {

/**
* 保存用户
* @param usre
* @return
*/
int save (User usre);
}
public class UserDaoImpl implements UserDao {


@Override
public int save(User user) {
return SqlsessionUtil.getSqlCurrentSqlsession().insert("save",user);
}
}


测试类

public void TESTUTILS(){
UserDao userDao=(UserDao) new TransactionHandler( new UserDaoImpl()).getProxy();
User user =new User();
user.setSex("男");
user.setName("的发生");[code=java]


int i=userDao.save(user);
System.out.println(i);
}[/code]

调试发现 第二次从threadlocal中取出的sqlsession是null
调试 第一次进入getSqlCurrentSqlsession():
    public static SqlSession getSqlCurrentSqlsession(){
SqlSession sqlSession=threadLocal.get(); //defaultsqlsession@1871
if (sqlSession==null){
sqlSession=sqlSessionFactory.openSession();
threadLocal.set(sqlSession);
}
return sqlSession;
}

第二次进入发现从threadlocal中取出来的是null,所以又重新创建了一个sqlsession 最后报错
    public static SqlSession getSqlCurrentSqlsession(){
SqlSession sqlSession=threadLocal.get(); //defaultsqlsession@1875
if (sqlSession==null){
sqlSession=sqlSessionFactory.openSession();
threadLocal.set(sqlSession);
}
return sqlSession;
}

报错代码为:
org.apache.ibatis.exceptions.PersistenceException:
### Error committing transaction. Cause: org.apache.ibatis.executor.ExecutorException: Cannot commit, transaction is already closed
### Cause: org.apache.ibatis.executor.ExecutorException: Cannot commit, transaction is already closed
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:227)
at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:218)
at com.li.utils.TransactionHandler.invoke(TransactionHandler.java:35)
at com.sun.proxy.$Proxy6.save(Unknown Source)
at com.li.test.TESTUTILS(test.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:292)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.apache.ibatis.executor.ExecutorException: Cannot commit, transaction is already closed
at org.apache.ibatis.executor.BaseExecutor.commit(BaseExecutor.java:239)
at org.apache.ibatis.executor.CachingExecutor.commit(CachingExecutor.java:119)
at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:224)
... 28 more
打印了一下线程,发现始终都是main线程
DEBUG - PooledDataSource forcefully closed/removed all connections.
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
DEBUG - Opening JDBC Connection
DEBUG - Created connection 2109839984.
DEBUG - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.Connection@7dc19a70]
DEBUG - ==> Preparing: insert into t_user(name,sex) values(?,?)
DEBUG - ==> Parameters: 的发生(String), 男(String)
DEBUG - <== Updates: 1
Thread[main,5,main]
DEBUG - Committing JDBC Connection [com.mysql.jdbc.Connection@7dc19a70]
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@7dc19a70]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.Connection@7dc19a70]
DEBUG - Returned connection 2109839984 to pool.
Thread[main,5,main]
Thread[main,5,main]
org.apache.ibatis.exceptions.PersistenceException:
### Error committing transaction. Cause: org.apache.ibatis.executor.ExecutorException: Cannot commit, transaction is already closed
### Cause: org.apache.ibatis.executor.ExecutorException: Cannot commit, transaction is already closed
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:227)
at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:218)
at com.li.utils.TransactionHandler.invoke(TransactionHandler.java:35)
at com.sun.proxy.$Proxy6.save(Unknown Source)
at com.li.test.TESTUTILS(test.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:292)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.jav
...全文
531 10 打赏 收藏 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
maradona1984 2021-01-18
  • 打赏
  • 举报
回复
感觉不对,为啥会拿到已经关闭的sqlsession对象才是问题所在,这个有点怪异
maradona1984 2021-01-18
  • 打赏
  • 举报
回复
删了SqlsessionUtil.close(sqlSession);
qq_38841290 2021-01-18
  • 打赏
  • 举报
回复
我之前重新创了一个项目 发现没问题 之后就配置了一下tomcat 不是maven上的插件(debug不习惯) 就又不行了
qq_38841290 2021-01-18
  • 打赏
  • 举报
回复
我一直都会得到两个 sqlsession 报错 太浪费时间了不研究了
编号灬9527 2021-01-18
  • 打赏
  • 举报
回复
拿你代码跑了下 没问题
Mi_Manchikkk 2021-11-04
  • 举报
回复
@编号灬9527 您用的idea是哪个版本
qq_38841290 2021-01-18
  • 打赏
  • 举报
回复
还是不行 懵逼了
qq_38841290 2021-01-18
  • 打赏
  • 举报
回复
链接:https://pan.baidu.com/s/1-dE6RojPOS3lWzrbfyjx2Q 提取码:79wx 复制这段内容后打开百度网盘手机App,操作更方便哦
qq_38841290 2021-01-18
  • 打赏
  • 举报
回复
我重新建了个项目发现没问题
编号灬9527 2021-01-18
  • 打赏
  • 举报
回复
项目打个包丢百度网盘分享下,有点意思, 不过看日志,connection已经被关闭了 DEBUG - Committing JDBC Connection [com.mysql.jdbc.Connection@7dc19a70] DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@7dc19a70] DEBUG - Closing JDBC Connection [com.mysql.jdbc.Connection@7dc19a70] DEBUG - Returned connection 2109839984 to pool. mybatis获取connection,通过Transaction接口,最终落到datasource获取connection,如果connection的autoCommit属性是True,那估计手动提交就翻车了

62,620

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧