项目场景:
由于目前接手的项目年代久远,在查看项目对于数据库的连接时尽然发下获取到SqlSession之后不会关闭,导致系统与数据库之间的连接被持续的消耗,所以需要重新将那些没有关闭的sqlsession进行关闭
问题描述:
由于项目涉及的后端代码文件较多不能够一一去查看所以需要一个工具能够快速的将那些没有关闭掉的session文件找出。
@Override
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReadFile {
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
private static String path = "D:\\needModifyFile\\";
/**
* 读取某个文件夹下的所有文件
*/
public static boolean getAllJavaFilePaths(String filepath) throws FileNotFoundException, IOException {
File srcFile = new File(filepath);
//获取该目录下所有的文件或者文件夹的File数组
File[] fileArray = srcFile.listFiles();
//遍历该File数组,得到每一个File对象
for (File file : fileArray) {
//判断该File对象是否是文件夹
if (file.isDirectory()) {
//递归调用
getAllJavaFilePaths(file.getPath());
} else {
//继续判断是否是以.java结尾
if (file.getName().endsWith(".java")) {
//就输出该文件的绝对路径
System.out.println(file.getAbsolutePath());
if (!checkMatch(file.getAbsolutePath())) {
writerFile(file.getAbsolutePath(), "needModifyFile", true);
}
}
}
}
return false;
}
public static void writerFile(String data, String fileName, Boolean isAppend) {
try {
String filePathName = path + "\\" + fileName + ".txt";
File file1 = new File(path);
//创建新文件夹,没有则新建。
if (!file1.exists()) {
file1.mkdirs();
}
File file = new File(filePathName);
if (!file.exists()) {
// 创建新文件,有同名的文件的话直接覆盖
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file, isAppend);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
//写入数据
bw.write(data + "\n");
//换行符,下一次写入时就会换行
bw.newLine();
bw.flush();
bw.close();
osw.close();
fos.close();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
}
public static boolean checkMatch(String path) {
//这里找到两个不同的字符串在文件当中出现的次数是否一致,有点类似于以前大学时期对于{}[]()括号是否匹配的题目
String str1 = "SqlSession sqlSession";
String str2 = "sqlSession.close()";
BufferedReader br = null;
boolean flag = false;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(path)), "utf-8"));
return (getCount(path, str1) == getCount(path, str2)) ? true : false;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}
public static int getCount(String path, String str1) throws IOException {
BufferedReader br = null;
int num = 0;
try {
br = new BufferedReader(new FileReader(path));
StringBuffer sb = new StringBuffer();
String str = null;
while ((str = br.readLine()) != null) {
sb.append(str);
}
String regex = str1;
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(sb);
while (matcher.find()) {
num++;
}
System.out.println("次数为: " + num);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (null != br) {
//关闭资源
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return num;
}
/*public static boolean deletefile(String delpath)
throws FileNotFoundException, IOException {
try {
File file = new File(delpath);
if (!file.isDirectory()) {
System.out.println("1");
file.delete();
} else if (file.isDirectory()) {
System.out.println("2");
String[] filelist = file.list();
for (int i = 0; i < filelist.length; i++) {
File delfile = new File(delpath + "\\" + filelist[i]);
if (!delfile.isDirectory()) {
System.out.println("path=" + delfile.getPath());
System.out.println("absolutepath="
+ delfile.getAbsolutePath());
System.out.println("name=" + delfile.getName());
delfile.delete();
System.out.println("删除文件成功");
} else if (delfile.isDirectory()) {
deletefile(delpath + "\\" + filelist[i]);
}
}
file.delete();
}
} catch (FileNotFoundException e) {
System.out.println("deletefile() Exception:" + e.getMessage());
}
return true;
}*/
public static void main(String[] args) {
try {
getAllJavaFilePaths("E:\\MyEclipseWorkSpace\\MyEclipse\\hd_mes\\src\\com\\seipher\\dwr\\");
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("ok");
}
}
解决方案:
根据上面的方法将sqlsession没有关闭掉的文件找出之后再考虑将Session在使用完成之后进行关闭。这里推荐两篇文章对于Mybatis线程池源码的分析。
MyBatis原理——DataSource分析及数据库连接池的实现
Mybatis的数据库连接池
总结
对于老的项目,由于之前的业务量并不是很大,导致这种基础问题一直没有被发现,并且由于使用的框架是Ibatis框架(之后更名为Mybatis)使用的线程池并没有对事务进行合理的管控导致系统长年处于比较卡顿的状态。在将一些session正确的关闭之后系统的流畅度会大幅提升。
SqlSession本身是比较昂贵的资源,各种开发组织都会使用线程池这种能够重复使用的session而不是重新openSession一个新的会话。