【問題描述】
單獨使用了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;
}
}