【问题描述】
单独使用了MyBatis框架,没有结合Spring框架,单独在SQL server Manager中查询数据的时候反应很快,但是在程序中查询特别慢,总是卡在查询的准备阶段。数据库那边能看到创建了很多个连接没有及时释放掉。
【分析原因】
上网查询了一些资料,一部分可能是查询语句本身的查询效率问题,一部分是MyBatis链接数据库的时候SqlSessionFactory创建了多个链接或者SqlSession没有及时关闭。
【解决方法】
1. 将创建SqlSessionFactory的方式改成单例模式,即只允许有且只有一个SqlSessionFactory实例存在。
2. SqlSession一旦创建需要及时关闭。
#-1->SqlSessionFactory的两种创建方式
#-1.1->静态模式创建SqlSessionFactory
单独创建一个名为【SessionFactory.java】文件。
放在static静态块中执行的代码只会执行一次,保证只创建了一个SqlSessionFactory。
package com.demo.tools;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.Reader;
public class DBtools {
public static SqlSessionFactory sessionFactory;
static {
try{
//配置文件地址
String resources = "com/demo/confg/mybatisconfg.xml";
//使用MyBatis提供的Resources类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader(resources);
//构建sqlSession的工厂
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
System.out.println("静态创建了一次SqlSessionFactory!");
}catch (Exception e){
e.printStackTrace();
}
}
//创建能执行映射文件中sql的sqlSession
public static SqlSession getSession()
{
return sessionFactory.openSession();
}
}
#-1.2->单例模式创建SqlSessionFactory
单独创建一个名为【SessionFactory.java】文件。
package com.slspt.tools;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.Reader;
public class SessionFactory {
private static SqlSessionFactory sqlSessionFactory;
private static SqlSessionFactory getSqlSessionFactory(){
//采用单例模式创建SqlSessionFactory
if(sqlSessionFactory == null){
try{
//配置文件地址
String resources = "com/slspt/confg/mybatisconfg.xml";
//使用MyBatis提供的Resources类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader(resources);
//构建sqlSession的工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
System.out.println("创建了一个sessionFactory!");
}catch (Exception e){
e.printStackTrace();
}
}
return sqlSessionFactory;
}
//创建能执行映射文件中sql的sqlSession
public static SqlSession getSession()
{
return getSqlSessionFactory().openSession();
}
}
#-2->SqlSession创建以后必须关闭
创建一个Service类来管理数据操作,注意session.commit() session.rollback() session.close()分别放在try-catch-finally块中
package com.services.Service;
import com.beans.DataBean;
import com.mappers.Mapper;
import com.tools.SessionFactory;
import org.apache.ibatis.session.SqlSession;
import java.util.ArrayList;
public class Service {
private SqlSession session;
private Mapper mapper;
public Service() {
super();
session = SessionFactory.getSession();
this.mapper = session.getMapper(Mapper.class);
System.out.println("创建了一个session链接!^_^");
}
public ArrayList<DataBean> selectAllCity(String DateString){
ArrayList<DataBean> listdata = new ArrayList<>();
session = SessionFactory.getSession();
try{
listdata = mapper.selectAllCity(DateString);
session.commit();
System.out.println("session提交!");
}catch (Exception e){
e.printStackTrace();
session.rollback();
}finally {
session.close();
System.out.println("session关闭!");
}
return listdata;
}
}
#-3->Bug记录:
Cause:org.apache.ibatis.executor.ExcutorException: Executor was closed.
原因:使用了已经关闭的session!通过打印输出可以看见session关闭的情况下,还在打印输出session关闭。
出现这种情况的原因是service里面一个session对应有多个Mapper:
构造函数中:
this.session = SessionFactory.getSession();
this.mapper = session.getMapper(YKSaleMapper.class);
this.datemapper = session.getMapper(YKSaleDateMapper.class);
解决办法:注意每个单独的函数给session初始化一遍,添加如下代码(如果单独 一个session对一个Mapper文件,加不加无所谓)
session = SessionFactory.getSession();
public ArrayList<String> getOperatorList(String Branch_no,String salechannel){
ArrayList<String> operatorList = new ArrayList<String>();
//每次给session初始化,避免出现bug【Executor was closed.】
session = SessionFactory.getSession();
//去数据库取list
try{
operatorList = mapper.selectDistOperator(Branch_no,salechannel);
session.commit();
System.out.println("session提交!");
}catch (Exception e){
e.printStackTrace();
session.rollback();
}finally {
session.close();
System.out.println("session关闭!");
}
return operatorList;
}
完整代码如下:
package com.sys.dao;
import com.sys.beans.PremiumBean;
import com.sys.beans.YKSaleBean;
import com.sys.mapper.YKSaleDateMapper;
import com.sys.mapper.YKSaleMapper;
import com.sys.tools.SessionFactory;
import org.apache.ibatis.session.SqlSession;
import java.util.ArrayList;
import java.util.HashMap;
public class YKSaleCityDao {
private SqlSession session;
private YKSaleMapper mapper;
private YKSaleDateMapper datemapper;
//构造函数
public YKSaleCityDao(){
super();
this.session = SessionFactory.getSession();
this.mapper = session.getMapper(YKSaleMapper.class);
this.datemapper = session.getMapper(YKSaleDateMapper.class);
}
private PremiumBean selectWithLike(String salechannel){
PremiumBean data = new PremiumBean();
//给session初始化避免出现使用已经关闭的session问题
session = SessionFactory.getSession();
try{
data = mapper.selectWithLike(salechannel);
session.commit();
System.out.println("session提交!");
}catch (Exception e){
e.printStackTrace();
session.rollback();
}finally {
session.close();
System.out.println("session关闭!");
}
return data;
}
//返回需要展示的list数据
public ArrayList<YKSaleBean> getUIList(String salechannel){
ArrayList<YKSaleBean> listdata = new ArrayList<YKSaleBean>();
for (int i = 0; i < insitutions.length; i++) {
YKSaleBean bean = new YKSaleBean();
//依次给Bean赋值
//将bean添加到list中
listdata.add(bean);
}
return listdata;
}
}