Java基础29--JDBCTools&ThreadLocal类

Java基础29–JDBCTools

为什么要工具类:
每次·连接数据库有些操作都是必写的,会有很多重复或者相似的代码,将这些代码提出来

一般都用连接池

JDBCTools第一个版本

public class JDBCToolsV1 {
	private static DataSource ds;//ds创建要么直接声明时初始化,要么static代码块里初始化,这里后面一种
	static{
		try {
			//静态代码块
			Properties pro = new Properties();
			pro.load(TestPools.class.getClassLoader().getResourceAsStream("druid.properties"));
			ds = DruidDataSourceFactory.createDataSource(pro);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	//抛出编译时异常
	public static Connection getConnection() throws SQLException{
		//方式一:DriverManager.getConnection()
		//方式二:连接池对象.getConnection(),基本用这个
		return ds.getConnection();
	}
	
	//把编译时异常转为运行时异常
	public static void free(Connection conn){
		try {
			if(conn != null){
				conn.close();
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);//转成运行时异常
		}
	}
	
	//这个方法只能用于不需要处理事务的情况
	//增、修改、删除、通用的update
	public static int update(String sql,Object... args) throws SQLException{
	//Object... args  0....n个?
		//获取连接
		Connection conn = getConnection();
		
		//创建PreparedStatement
		PreparedStatement ps = conn.prepareStatement(sql);
		
		//设置?
		if(args!=null && args.length>0){
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i+1, args[i]);
			}
		}
		
		//执行sql
		int len = ps.executeUpdate();
		
		ps.close();
		free(conn);
		
		return len;
		
	}
	
@Test
	public void test01() throws SQLException{
		//添加一个部门到test库的t_department
		String sql = "INSERT INTO `t_department` VALUES(NULL,?,?) ";
		int len = JDBCToolsV1.update(sql, "测试部门1" ,"测试部门简介1");
		System.out.println(len>0?"success":"fail");
	}

}

运行成功
若是事务

@Test
	public void test02() throws SQLException{
		String sql1 = "UPDATE t_department SET description = 'xx' WHERE did = 5183";
		String sql2 = "UPDATE t_department SET description = 'yy' did = 5";//这个sql是故意写错的
		//希望它俩是构成一个事务的
		//直接用这个,没法处理事务
		//要么同时成功。要么同时失败
		JDBCToolsV1.update(sql1);
		JDBCToolsV1.update(sql2);
	}

会发现一个成功,一个失败,直接用这个,没法处理事务,说明这个update方法只能用于不需要处理事务的情况

若是不要上面那个update方法,让它处理事务

@Test
	public void test03() throws SQLException{
		String sql1 = "UPDATE t_department SET description = 'xx' WHERE did = 5183";
		String sql2 = "UPDATE t_department SET description = 'yy' where did = 5";//这个sql是故意写错的
		
		//希望它俩是构成一个事务的
		Connection conn = JDBCToolsV1.getConnection();
		conn.setAutoCommit(false);
		PreparedStatement pst1 = conn.prepareStatement(sql1);
		PreparedStatement pst2 = conn.prepareStatement(sql2);
		try {
			int len1 = pst1.executeUpdate();
			int len2 = pst2.executeUpdate();
			
			if(len1>0 && len2>0){
				conn.commit();
			}else{
				conn.rollback();
			}
		} catch (Exception e) {
			conn.rollback();
		}
		
		pst1.close();
		pst2.close();
		conn.setAutoCommit(true);
		JDBCToolsV1.free(conn);
	}

运行正常,但是还是有很多重复代码

若是写为

	public static int update2(String sql,Object... args) throws SQLException{
		//获取连接
		Connection conn = getConnection();
		//conn.setAutoCommit(false);//若是在这里设置,不能保证测试方法里两个sql是同一个事务,test05测试不通过
		
		//创建PreparedStatement
		PreparedStatement ps = conn.prepareStatement(sql);
		
		//设置?
		if(args!=null && args.length>0){
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i+1, args[i]);
			}
		}
		
		//执行sql
		int len = 0;
		try {
			len = ps.executeUpdate();
			conn.commit();
		} catch (Exception e) {
			conn.rollback();
		}
		
		ps.close();
		conn.setAutoCommit(true);
		free(conn);
		
		return len;
	}

@Test
	public void test04()throws Exception{
		String sql1 = "UPDATE t_department SET description = 'xx' WHERE did = 5183";
		String sql2 = "UPDATE t_department SET description = 'yy' where did = 5";//这个sql是故意写错的
		
		//希望它俩是构成一个事务的
		Connection conn = JDBCToolsV1.getConnection();
		conn.setAutoCommit(false);
		
		try {
			int len1 = JDBCToolsV1.update(conn, sql1);
			int len2 = JDBCToolsV1.update(conn, sql2);
			if(len1 > 0 && len2>0){
				conn.commit();
			}else{
				conn.rollback();
			}
		} catch (Exception e) {
			conn.rollback();
		}
		
		conn.setAutoCommit(true);
		JDBCToolsV1.free(conn);
		//可以正常运行,但不规范
	}
	@Test
	public void test05()throws Exception{
		String sql1 = "UPDATE t_department SET description = 'xx' WHERE did = 5183";
		String sql2 = "UPDATE t_department SET description = 'yy' did = 5";//这个sql是故意写错的
		
//		JDBCToolsV1.update2(sql1);
//		JDBCToolsV1.update2(sql2);
	}

ThreadLocal类介绍

JDK 1.2的版本中就提供java.lang.ThreadLocal,为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。通常用来在在多线程中管理共享数据库连接、Session等

ThreadLocal用于保存某个线程共享变量,原因是在Java中,每一个线程对象中都有一个ThreadLocalMap<ThreadLocal, Object>,其key就是一个ThreadLocal,而Object即为该线程的共享变量。而这个map是通过ThreadLocal的set和get方法操作的。对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。

1、ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值。

2、ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值。

3、ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。

public class TestTools{
	public static void main(String[] args) {
		MyThread m1 = new MyThread();
		m1.start();
		
		MyThread m2 = new MyThread();
		m2.start();
	}
}
class Tools {
	private static Random rand = new Random();//产生随机数的工具类
	private static ThreadLocal<Integer> th = new ThreadLocal<Integer>();
	
	public static void setNumber(){
		th.set(rand.nextInt(100));//这里设置的就是当前线程保存的共享变量,这个共享变量不是我们之前说的多个线程之间共享,是说的是同一个线程在整个生命周期中,使用的共享变量
	}
	
	public static int getNumber(){
		return th.get();
	}
}
class MyThread extends Thread{
	public void run(){
		Tools.setNumber();
		
		for (int i = 0; i < 5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			int number = Tools.getNumber();
			System.out.println(Thread.currentThread().getName() +":"+ number);
		}
	}
}

在这里插入图片描述
不管什么时候拿,不管生命周期过久,同一个线程对象拿的值始终是相等的

JDBCTools第二个版本

public class JDBCToolsV2 {
	private static DataSource ds;
	private static ThreadLocal<Connection> th;
	
	static{
		try {
			//静态代码块
			Properties pro = new Properties();
			pro.load(TestPools.class.getClassLoader().getResourceAsStream("druid.properties"));
			ds = DruidDataSourceFactory.createDataSource(pro);
			th = new ThreadLocal<Connection>();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	//抛出编译时异常
	public static Connection getConnection() throws SQLException{
		//方式一:DriverManager.getConnection()
		//方式二:连接池对象.getConnection()
		Connection conn = th.get();//获取当前线程中的共享的连接对象
    // conn.setAutoCommit(false);不能写这里,可能会重复
		if(conn == null){//当前线程没有拿过连接,第一个获取连接
			conn = ds.getConnection();//从连接池中拿一个新的
			th.set(conn);//放到当前线程共享变量中
		}
		return conn;
	}
	
	//把编译时异常转为运行时异常
	public static void free(Connection conn){
		try {
			if(conn != null){
				conn.close();
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static int update(String sql,Object... args) throws SQLException{
		Connection conn = getConnection();
		PreparedStatement pst = conn.prepareStatement(sql);
		if(args!=null && args.length>0){
			for (int i = 0; i < args.length; i++) {
				pst.setObject(i+1, args[i]);
			}
		}
		
		int len = pst.executeUpdate();
		pst.close();
		//conn.setAutoCommit(true);不能写这里,可能会重复
		return len;
	}
}

	public static void main(String[] args) throws SQLException {
		String sql1 = "UPDATE t_department SET description = 'xx' WHERE did = 5183";
		String sql2 = "UPDATE t_department SET description = 'yy' where did = 5";//这个sql是故意写错的
		
		Connection conn = JDBCToolsV2.getConnection();
		conn.setAutoCommit(false);
		
		try {
			JDBCToolsV2.update(sql1);
			JDBCToolsV2.update(sql2);
			conn.commit();
		} catch (Exception e) {
			e.printStackTrace();
			conn.rollback();
		}
		
		conn.setAutoCommit(true);
		JDBCToolsV2.free(conn);
	}

没有传connection对象,只是传来sql,但update方法里能保证是同一个对象

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值