static
的。普通的static
变量是所有线程共享的,ThreadLocal 的静态变量只在当前线程中共享,多个线程之间的线程变量是彼此隔离的。案例看点:对比普通静态变量和线程静态变量
public class ThreadLocalTest {
// 全局静态变量,所有线程共享
public static Integer integer=null;
// 线程静态变量,单个线程共享,不同线程具有不同的数据副本(值)
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
// 定义内部线程类
public static class Task implements Runnable{
@Override
public void run() {
// 产生随机数
Integer i = new Random().nextInt(100);
// 设置线程变量的值
threadLocal.set(i);
// 保存到普通静态变量
integer = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 获得线程变量的值
Integer ii = threadLocal.get();
System.out.println("线程"+Thread.currentThread().getName()+" 的threadLocal="+ii);
System.out.println("线程"+Thread.currentThread().getName()+" 的integer="+integer);
}
}
public static void main(String[] args) {
// 启动三个线程
for (int i = 0; i < 3; i++) {
new Thread(new Task()).start();
}
}
}
运行结果,可以看出
线程Thread-1 的threadLocal=40
线程Thread-0 的threadLocal=33
线程Thread-1 的integer=40
线程Thread-2 的threadLocal=88
线程Thread-2 的integer=40
线程Thread-0 的integer=40
案例看点:整合了动态代理、ThreadLocal、commons-dbutils
database.properties
连接信息配置# 驱动类
driver=com.mysql.cj.jdbc.Driver
# 连接字符串
url=jdbc:mysql://localhost:3306/jsp?useUnicode=true&serverTimezone=GMT&characterEncoding=UTF-8&useSSL=false
# 连接字符串:解决 PublicKey.. 异常
#url=jdbc:mysql://localhost:3306/jsp?useUnicode=true&serverTimezone=GMT&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true
# 用户名
user=root
# 密码
password=1234
ConfigManager.java
连接信息读取类public class ConfigManager {
private static Properties props = null;
static {
InputStream is = null;
is = ConfigManager.class.getClassLoader().getResourceAsStream(
"database.properties");
if (is == null)
throw new RuntimeException("找不到数据库参数配置文件!");
props = new Properties();
try {
props.load(is);
} catch (IOException e) {
throw new RuntimeException("数据库配置参数加载错误!", e);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String getProperty(String key) {
return props.getProperty(key);
}
}
ConnectionManager.java
连接管理类public class ConnectionManager {
private static String driver = ConfigManager.getProperty("driver");// 数据库驱动字符串
private static String url = ConfigManager.getProperty("url");// 连接URL字符串
private static String user = ConfigManager.getProperty("user"); // 数据库用户名
private static String password = ConfigManager.getProperty("password"); // 用户密码
// 使用ThreadLocal线程变量保存并共享Connection连接对象
static ThreadLocal<Connection> threadLocalConnection = new ThreadLocal<>();
// 静态块加载驱动
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
// 取得线程变量中的Connection连接对象
Connection conn = threadLocalConnection.get();
if(conn == null){
try {
conn = DriverManager.getConnection(url,user,password);
// 保存到线程变量中
threadLocalConnection.set(conn);
// 将连接的事务设置为手动提交,自动提交设置为false
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
/**
* 提交事务
*/
public static void commit(){
Connection conn = threadLocalConnection.get();
if(conn != null){
try {
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
//一定要执行remove()操作,否则会出错。(因为Tomcat服务器底层使用了线程池技术)
threadLocalConnection.remove();
}
/**
* 提交事务
*/
public static void rollback(){
Connection conn = threadLocalConnection.get();
if(conn != null){
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
//一定要执行remove()操作,否则会出错。(因为Tomcat服务器底层使用了线程池技术)
threadLocalConnection.remove();
}
}
TransactionProxyFactory.java
动态代理类,代理实现业务逻辑层的事务控制public class TransactionProxyFactory {
public static <T> T create(Class<T> clazz){
Enhancer enhancer = new Enhancer();
// 采用接口内部类的方式实现代理功能
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开始事务。。。。");
Object result = null;
try {
// 核心业务,调用父类的方法
result = methodProxy.invokeSuper(target,objects);
System.out.println("提交...");
ConnectionManager.commit();
}catch (Exception e){
System.out.println("回滚...");
ConnectionManager.rollback();
e.printStackTrace();
}
return result;
}
});
// 设置代理类的父类
enhancer.setSuperclass(clazz);
// 返回创建的动态代理类对象
return (T) enhancer.create();
}
}
BaseDao.java
使用并封装了commons-dbutils
的基本操作/**
* 执行数据库操作的工具类。
*/
public class BaseDao<T> {
private QueryRunner queryRunner = new QueryRunner();
/**
* 执行增删该操作
* @param sql
* @param args
* @return 返回受影响的行数
*/
public int update(String sql,Object ... args){
Connection conn = ConnectionManager.getConnection();
try {
return queryRunner.update(conn,sql,args);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 查询返回一个实体类对象
* @param type
* @param sql
* @param args
* @return
*/
public T queryForOne(Class<T> type,String sql,Object...args){
Connection conn = ConnectionManager.getConnection();
try {
T query = queryRunner.query(conn, sql, new BeanHandler<T>(type), args);
return query;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 查询返回一个实体类对象集合
* @param type
* @param sql
* @param args
* @return
*/
public List<T> queryForList(Class<T> type, String sql, Object...args){
Connection conn= ConnectionManager.getConnection();
try {
return queryRunner.query(conn, sql, new BeanListHandler<T>(type), args);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 查询返回一个数据,如统计记录的行数
* @param sql
* @param args
* @return
*/
public Object queryForSingleValue(String sql,Object...args){
Connection conn = ConnectionManager.getConnection();
try {
return queryRunner.query(conn,sql, new ScalarHandler(),args);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
UserDaoImpl.java
基本DAO类public class UserDaoImpl extends BaseDao<User> implements UserDao {
@Override
public int insert(User user) throws SQLException {
String sql = "insert into users(userName,password,realName) values(?,?,?)";
return super.update(sql,
user.getUserName(),
user.getPassword(),
user.getRealName());
}
}
UserService.java
业务逻辑类public class UserService {
UserDao userDao = new UserDaoImpl();
/**
* 批量添加,多个User要么全部添加成功,要么全部添加失败
* @param users
* @throws SQLException
*/
public void insert(List<User> users) throws SQLException {
// 业务类中只关注核心功能,事务控制交给动态代理
for (User user : users) {
userDao.insert(user);
}
}
}
UserServiceTest.java
测试类public class UserServiceTest {
@Test
public void insert() throws SQLException {
User user1 = new User();
user1.setUserName("雷老板");
user1.setPassword("1");
user1.setRealName("是我雷老板");
User user2 = new User();
user2.setUserName("雷老板2");
// 数据太长了,会添加失败
user2.setRealName("雷老板222雷老板222雷老板222雷老板222雷老板222雷老板222雷老板222雷老板222雷老板222雷老板222雷老板222雷老板222雷老板222");
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
// 使用动态代理来创建业务逻辑层的类
UserService userService = TransactionProxyFactory.create(UserService.class);
userService.insert(users);
}
}