最近才学mybatis
创建了两张表,一张activity表,一张user表
我想接受前端的loginAct和其他数据,通过loginAct在user表中查找userId,再将id和其他的数据保存在activity表中,可是在查找user时一直报错
这是相关类
//这是dao和service的实现类
public interface UserDao {
User login(@Param("loginAct") String loginAct,
@Param("loginPwd") String loginPwd);
List<User> getUserList();
User findByLoginAct(String loginAct);
}
public class UserServiceImpl implements UserService {
private UserDao userDao = SqlSessionUtil.getSession().getMapper(UserDao.class);
@Override
public User login(String loginAct, String loginPwd, String ip) throws LoginException {
User user = userDao.login(loginAct, loginPwd);
if (user == null){
throw new LoginException("用户名或密码错误");
}
if (user.getExpireTime().compareTo(DataUtil.getSystimestamp()) < 0){
throw new LoginException("时间已失效");
}
if (!"1".equals(user.getLockState())){
throw new LoginException("已锁定");
}
if (!ip.equals(user.getAllowIps())){
throw new LoginException("非合法ip");
}
return user;
}
@Override
public List<User> getUserList() {
return userDao.getUserList();
}
@Override
public User findByLoginAct(String loginAct) {
return userDao.findByLoginAct(loginAct);
}
}
public interface ActivityDao {
int save(Activity activity);
List<Activity> getActiveTable(Activity activity);
}
public class ActivityServiceImpl implements ActivityService {
private final ActivityDao activityDao = (ActivityDao) SqlSessionUtil.getSession().getMapper(ActivityDao.class);
@Override
public boolean save(Activity activity){
boolean flag = true;
int count = activityDao.save(activity);
if (count != 1) {flag = false;}
return flag;
}
@Override
public List<Activity> getActiveTable(Activity activity, int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
return activityDao.getActiveTable(activity);
}
}
//这里下面是工具类
public class SqlSessionUtil {
private SqlSessionUtil() {}
private static SqlSessionFactory sqlSessionFactory = null;
private static ThreadLocal<SqlSession> t = new ThreadLocal<>();
static {
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSession(){
SqlSession session = t.get();
if (session == null) {
session = sqlSessionFactory.openSession();
t.set(session);
}
return session;
}
public static void close(SqlSession session){
session.close();
t.remove();
}
}
public class Handler implements InvocationHandler {
Object target = null;
public Handler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession session = null;
Object obj = null;
try {
session = SqlSessionUtil.getSession();
obj = method.invoke(target, args);
session.commit();
} catch (Exception e) {
if (session != null) {
session.rollback();
}
e.printStackTrace();
throw e.getCause();
} finally {
SqlSessionUtil.close(session);
}
return obj;
}
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
}
public class ServiceFactory {
public static Object getService(Object service){
return new Handler(service).getProxy();
}
}
这是我的mapper.xml
<mapper namespace="com.terfation.crm.settings.dao.UserDao">
<select id="login" resultType="User">
select *
from tbl_user
where loginAct=#{loginAct} and loginPwd = #{loginPwd}
</select>
<select id="getUserList" resultType="User">
select *
from tbl_user
</select>
<select id="findByLoginAct" resultType="User">
select *
from tbl_user
where loginAct = #{loginAct}
</select>
</mapper>
<mapper namespace="com.terfation.crm.workbench.dao.ActivityDao">
<insert id="save">
insert
into tbl_activity (
id, owner, name, startDate, endDate, cost, description, createTime, createBy)
values (
#{id},
#{owner},
#{name},
#{startDate},
#{endDate},
#{cost},
#{description},
#{createTime},
#{createBy})
</insert>
</mapper>
这是测试代码
@org.junit.Test
public void test1(){
UserService userService = (UserService) ServiceFactory.getService(new UserServiceImpl());
ActivityService activityService = (ActivityService) ServiceFactory.getService(new ActivityServiceImpl());
User user = userService.findByLoginAct("root");
Activity activity = new Activity();
activity.setId("123");
activity.setName("123");
activityService.save(activity);//这里报错
}
@org.junit.Test
public void test(){
UserService userService = (UserService) ServiceFactory.getService(new UserServiceImpl());
ActivityService activityService = (ActivityService) ServiceFactory.getService(new ActivityServiceImpl());
Activity activity = new Activity();
activity.setId("123");
activity.setName("123");
activityService.save(activity);
User user = userService.findByLoginAct("root");//调换位置后这里报错
}
//单独运行两个都没有问题
//单独调试findByLoginAct又出现错误
@org.junit.Test
public void tryFind(){
UserService userService = (UserService) ServiceFactory.getService(new UserServiceImpl());
User user = userService.findByLoginAct("root");
System.out.println(user.getId());
}
@org.junit.Test
public void trySave(){
ActivityService activityService = (ActivityService) ServiceFactory.getService(new ActivityServiceImpl());
Activity activity = new Activity();
activity.setId("123");
activity.setName("123");
activityService.save(activity);
}
这是两个调换前的错误信息
这是两个调换后的错误信息
错误原因:
在第一次创建SQL session查询时进入了代理类的的invoke方法中
try {
session = SqlSessionUtil.getSession();
obj = method.invoke(target, args);
session.commit();
} catch (Exception e) {
if (session != null) {
session.rollback();
}
e.printStackTrace();
throw e.getCause();
} finally {
SqlSessionUtil.close(session);
}
此时提交后进入finally中调用工具类将sqlsession关闭了
在下一次执行操作时还是调用的原来的sqlsession创建的dao对象中的方法
private final ActivityDao activityDao = (ActivityDao) SqlSessionUtil.getSession().getMapper(ActivityDao.class);
虽然代理类对象调用工具类方法重新获取了到了一个新的sqlsession,但是原来创建dao对象的sqlsession已经关闭了
关于原本没问题的代码,调试时报错,好像是因为idea debug展现变量 会调用变量的toString方法才产生问题,原因不清除,日后再找错
这个问题我解决了,主要是因为private UserDao userDao = SqlSessionUtil.getSession().getMapper(UserDao.class);这行代码,
当你用mybatis自动生成dao实现类机制时候,mybatis底层是会调用原来的SqlSession对象的,但是之前的SqlSession对象被你一次使用后关闭了SqlSessionUtil.close(session);
所以之后会报Executor was closed,执行者被关闭错误,有两种解决办法:
1.你可以将UserDao userDao = SqlSessionUtil.getSession().getMapper(UserDao.class);这行代码放到方法中,
每次调用生成新的UserDao对象,mybatis底层也会调用新的SqlSession对象,这是我采用的办法
2.可以选择一次会话不关闭SqlSession对象,用户关闭浏览器才SqlSession.close(),(我更偏向于这个方法,但是还没想到怎么实现)
insert标签,需要指定传参。
<insert id="save" parameterType=“”>