八、使用ThreadLocal绑定SqlSession优化思想

ThreadLocal:线程容器,给线程绑定一个 Object 内容,后只要线程不变,可以随时取出.

注意:如果改变了线程,无法取出内容.

代码示例:

final ThreadLocal<String> threadLocal = newThreadLocal<>();
threadLocal.set("测试");
new Thread(){
    public void run() {
        String result = threadLocal.get();
        System.out.println("结果:"+result);
        };
    }.start();

我们使用ThreadLocal来优化一下之前写的项目:

实体类:

package com.tao.pojo;

public class Log {
	private int id;
	private String accIn;
	private String accOut;
	private double money;
	
	public Log() {

	}

	public Log(int id, String accIn, String accOut) {
		this.id = id;
		this.accIn = accIn;
		this.accOut = accOut;
	}

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getAccIn() {
		return accIn;
	}
	public void setAccIn(String accIn) {
		this.accIn = accIn;
	}
	public String getAccOut() {
		return accOut;
	}
	public void setAccOut(String accOut) {
		this.accOut = accOut;
	}
	public double getMoney() {
		return money;
	}
	public void setMoney(double money) {
		this.money = money;
	}
	@Override
	public String toString() {
		return "Log [id=" + id + ", accIn=" + accIn + ", accOut=" + accOut + ", money=" + money + "]";
	}
}

映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tao.mapper.LogMapper">
	<insert id="insertLog" parameterType="Log">
		insert into log values(default,#{accIn},#{accOut},#{money})
	</insert>
</mapper>

映射接口:

package com.tao.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.tao.pojo.Log;

public interface LogMapper {
    int insertLog(Log log);
}

service处理:

package com.tao.service;

import com.tao.pojo.Log;

/**
 * 日志逻辑处理层
 */
public interface LogService {
	
	/**
	 * 增加转账记录
	 * @return
	 */
	int addLog(Log log);
}

service实现:省略了 读取配置文件、获取session 、提交session 、回滚、 关闭session等代码

package com.tao.service.impl;

import org.apache.ibatis.session.SqlSession;

import com.tao.mapper.LogMapper;
import com.tao.pojo.Log;
import com.tao.service.LogService;
import com.tao.util.MyBatisUtil;

public class LogServiceImpl implements LogService{

	@Override
	public int addLog(Log log) {
		SqlSession session = MyBatisUtil.getSqlSession();
		LogMapper logMapper = session.getMapper(LogMapper.class);
		return logMapper.insertLog(log);
	}

}

控制层:

package com.tao.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.tao.pojo.Log;
import com.tao.service.LogService;
import com.tao.service.impl.LogServiceImpl;

@WebServlet("/insertLog")
public class LogServlet extends HttpServlet{

	private static final long serialVersionUID = 1L;
	
	private LogService logService = new LogServiceImpl();
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("utf-8");
		resp.setContentType("text/html;charset=utf-8");
		Log log = new Log();
		log.setAccIn(req.getParameter("accIn"));
		log.setAccOut(req.getParameter("accOut"));
		log.setMoney(Double.parseDouble(req.getParameter("money")));
		int index = logService.addLog(log);
		if(index>0){
			resp.sendRedirect("success.jsp");
		}else{
			resp.sendRedirect("error.jsp");
		}
		
		
	}
}

过滤器:把省略的代码,在控制层执行前后加上处理 也就相当于在service前后加了处理 责任链模式:

package com.tao.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

import org.apache.ibatis.session.SqlSession;

import com.tao.util.MyBatisUtil;
/**
 * 最开始是由Spring框架提出的.整合Hibernate框架是使用的是OpenSessionInView
 * @author zhangtao
 *
 */
@WebFilter("/*")
public class openSessionViewFilter implements Filter{

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		SqlSession session = MyBatisUtil.getSqlSession();
		try {
			filterChain.doFilter(servletRequest, servletResponse);
			session.commit();
		} catch (Exception e) {
			session.rollback();
			e.printStackTrace();
		}finally {
			MyBatisUtil.closeSession();
		}
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		
	}

}

 使用ThreadLocal封装MyBatisUtil工具类:

package com.tao.util;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtil {
	
	private static SqlSessionFactory factory;
	private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
	
	static{
		try{
			InputStream is = Resources.getResourceAsStream("mybatis.xml");
			factory = new SqlSessionFactoryBuilder().build(is);
		}catch(IOException e){
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取SqlSession的方法
	 */
	public static SqlSession getSqlSession(){
		SqlSession session = threadLocal.get();
		if(session==null){
			threadLocal.set(factory.openSession());
		}
		return threadLocal.get();
	}
	
	/**
	 * 关闭Session的方法
	 */
	public static void closeSession(){
		SqlSession session = threadLocal.get();
		if(session!=null){
			session.close();
		}
		threadLocal.set(null);
	}
}

mybaits核心配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  
<configuration>
	
	<!-- mybatis 开启log4j支持功能 -->
	<settings>
		<setting name="logImpl" value="LOG4J"/>
	</settings>
	
	<!-- 给某个包下所有类起别名,别名为类名, 不区分大小写 -->
	<typeAliases>
		<package name="com.tao.pojo"/>
	</typeAliases>
	
	<environments default="dev">
		<environment id="dev">
			<!-- JDBC 原生事务管理方式 -->
			<transactionManager type="JDBC"></transactionManager>
			
			<!-- 使用数据库连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
				<property name="username" value="root"/>
				<property name="password" value="root"/>
			</dataSource>
		</environment>
	</environments>
	
	<mappers>
		<!-- <mapper resource="com/tao/mapper/LogMapper.xml"/> -->
		<package name="com.tao.mapper"/>
	</mappers>


</configuration>

index.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="insertLog" method="post">
<table>
	<tr>
		<td>转账账号:<input type="text" name="accOut" ></td>
		<td>收账账号:<input type="text" name="accIn"></td>
		<td>转账金额:<input type="text" name="money"></td>
		<td><input type="submit" value="确认转账"></td>
	</tr>
</table>

</form>
</body>
</html>

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocal<SqlSession>是一种Java中的线程局部变量,用于在多线程环境下维护变量的独立性。在MyBatis中,可以使用ThreadLocal<SqlSession>来实现多线程下的SqlSession实例的独立性,避免多个线程共享同一个SqlSession实例而导致的线程安全问题。 下面是一个使用ThreadLocal<SqlSession>的示例代码: ```java public class MyBatisUtil { private static ThreadLocal<SqlSession> sqlSessionThreadLocal = new ThreadLocal<>(); public static SqlSession getSqlSession() { SqlSession sqlSession = sqlSessionThreadLocal.get(); if (sqlSession == null) { sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession(); sqlSessionThreadLocal.set(sqlSession); } return sqlSession; } public static void closeSqlSession() { SqlSession sqlSession = sqlSessionThreadLocal.get(); if (sqlSession != null) { sqlSession.close(); sqlSessionThreadLocal.remove(); } } } ``` 在上述代码中,我们使用了一个静态的ThreadLocal<SqlSession>变量来维护SqlSession实例的独立性。在getSqlSession()方法中,我们首先从ThreadLocal中获取当前线程对应的SqlSession实例,如果不存在则创建一个新的SqlSession实例并存储到ThreadLocal中,最后返回该SqlSession实例。在closeSqlSession()方法中,我们从ThreadLocal中获取当前线程对应的SqlSession实例并关闭它,然后从ThreadLocal中移除该SqlSession实例。 使用ThreadLocal<SqlSession>可以有效地避免多线程下的SqlSession实例共享问题,从而保证了程序的线程安全性。 --相关问题--: 1. 什么是线程安全问题? 2. MyBatis中的SqlSession有哪些常用方法? 3. 如何在My

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值