关于使用Mybatis时SqlSession的报错:Excutor was closed的解决办法。(使用了threadlocal)
由于sqlsession是非线程安全的,因此在做sqlSession工具类的时候请讲SqlSession置于方法体中,不要使用与全局变量中。
以下问题基于将seatDAO放入全局变量中,导致了这个问题
public class ReserveServlet02 extends HttpServlet {
private SeatMapper seatDAO;//全局变量
//业务代码...
}
-
init()中不能使用try - with -resource
public void init() { try (SqlSession session = DBUtil2.openSession()) { seatDAO = session.getMapper(SeatMapper.class); } }
修改后代码
public void init() { seatDAO = (SeatMapper) DBUtil2.openSession().getMapper(SeatMapper.class); }
-
每次连接了数据库都需要重新打开,再关闭.因为我使用了一个全局的sqlSession,这个sqlSession close()之后,其他业务功能就不能再使用这个sqlSession了。除非再次把它打开。笨拙的办法就是在每个业务功能上添加这两行代码:
SqlSession sqlSession2 = DBUtil2.openSession();//添加事务 seatDAO = sqlSession2.getMapper(SeatMapper.class); //用完之后记得关闭,不关也行,但是threadlocal就没有意义了
以下是修改前的实例代码:
try {
lock.lock();//上锁,保证线程安全
Seat seat = seatDAO.getSeatById(seatId);
//没有调用DBUtil2.openSession().getMapper(),出现Excutor was closed问题
if (seat != null && seat.getStatus() == 1) {
seat.setStatus(2);
SqlSession sqlSession2 = DBUtil2.openSession();//添加事务
seatDAO = sqlSession2.getMapper(SeatMapper.class);
isSuccess = seatDAO.updateSeat(seat);
sqlSession2.commit();
DBUtil2.close(sqlSession2);
}
} finally {
lock.unlock();//记得解锁
}
return isSuccess;
}
修改后的代码
try {
lock.lock();
SqlSession sqlSession = DBUtil2.openSession();
seatDAO = sqlSession.getMapper(SeatMapper.class);
Seat seat = seatDAO.getSeatById(seatId);
DBUtil2.close(sqlSession);
//添加了DBUtil2.openSession().getMapper()方法后,运行正常
if (seat != null && seat.getStatus() == 1) {
seat.setStatus(2);
SqlSession sqlSession2 = DBUtil2.openSession();//添加事务
seatDAO = sqlSession2.getMapper(SeatMapper.class);
isSuccess = seatDAO.updateSeat(seat);
sqlSession2.commit();
DBUtil2.close(sqlSession2);
}
} finally {
lock.unlock();
}
return isSuccess;
}
总结:修改后还是有问题,下次再解决。第一次有用,第二次之后就是有时候有用有时候没用,可能是别的部分代码有问题,也可能这种修改方式有问题,目前也不知道原理。可以尝试一下不要定义为全局变量,可能可以完美的解决问题,也是明天再试