druid、dbutils

本文详细介绍了阿里德鲁伊数据库连接池的原理及应用,包括如何通过配置文件设置参数,利用ThreadLocal确保线程安全,以及使用QueryRunner简化数据库操作。探讨了连接池技术在提高效率和资源复用方面的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相关jar包
在这里插入图片描述
相关数据库
users
在这里插入图片描述
druid.properties

url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
username=root
password=123456
driverClassName=com.mysql.jdbc.Driver
initialSize=10
maxActive=20
maxWait=1000

utils

/*
 * 问题1:注册驱动,获取连接等写了很多遍
 * 问题2:我们每次都从数据库获取新的连接
 * 	mysql是一个TCP/IP协议的网络程序,那么:
 * (1)每获取一次新的连接的成本很高,需要“三次握手”,断开需要“四次挥手”等过程
 * (2)每一个客户端都有单独的线程来维护它的通信
 * 这样就会造成如果有很多的客户端同时去连接mysql服务器,会造成
 * (1)mysql的并发量就有风险,如果太多就会挂了,
 * 	特别是遇到一些程序员,获取完连接,没有关闭。
 * (2)每次高成本获取的连接只用一次,太奢侈了,我们希望可以重复使用连接对象。
 * 
 * 
 * 解决:
 * (1)解决问题1:我们把注册驱动,获取连接等方法,封装到一个工具类中,减少代码
 * (2)解决问题2:我们可以使用“数据库连接池”来解决
 * 
 * 数据库连接池的技术:
 * (1)先创建一个连接池pool,然后在池中先放一些连接对象,然后程序去获取连接对象时,用先有的对象,会更快。
 * 例如:从自来水新接一桶水,没有从游泳池中直接“装”一桶水快。
 * 
 * (2)然后我们可以设置连接池的最大连接数量,如果池中的所有连接都在使用的话,那么可以让“客户端”等待,
 * 虽然有等待的现象,但是总被“挂”了好。
 * 
 * (3)创建连接池时,一开始是初始化少量的连接,等用户并发量上来后,会增加连接数,直到最高连接数为止。
 * 
 * (4)之前conn.close()真正的与服务器断开连接,现在从连接池中拿的连接对象,关闭时是还给连接池。
 * 
 * 连接池技术有很多,我们讲的是德鲁伊,它是阿里的。
 * 
 * 使用步骤:
 * (1)引入"德鲁伊"jar
 * druid-1.1.10.jar
 * 
 * (2)加一个配置文件
 * 配置“德鲁伊"连接池的参数
 * 
 * 明确:数据库连接池的作用,管理连接。
 *   为了获取连接,需要哪些参数:主机名、端口号、用户名、密码、驱动类名
 *   		其他参数:初始化连接数,最多连接数...
 * 
 * 在src下建一个druid.properties文件
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
username=root
password=123456
driverClassName=com.mysql.jdbc.Driver
initialSize=10
maxActive=20
maxWait=1000
filters=wall
 * 
 * (3)创建连接池(一个系统一个)
 * 
 * javax.sql.DataSource 
 * 
 * (4)提供一个方法,可以从数据库连接池中拿连接对象
 * (5)提供一个关闭连接的方法
 */
public class JdbcUtils {
	private static DataSource ds ;
	
	private static ThreadLocal<Connection> local;
	
	static{
		try {
			//静态代码块可以初始化静态变量
//		(1)把src下建一个druid.properties文件的数据,加载到一个Properties对象中
			Properties pro = new Properties();
			pro.load(JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
			
			ds = DruidDataSourceFactory.createDataSource(pro);
			
			local = new ThreadLocal<>();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	//这个代码不能保证同一个线程(客户端)共享同一个连接对象,我们后面的代码如果需要事务处理,就有问题
/*	public static Connection getConnection() throws SQLException{
		//这里只是改变获取连接的代码
		return ds.getConnection();
	}*/
	
	//这里修改为用ThreadLocal来保存同一个线程的共享变量
	public static Connection getConnection() throws Exception{
		//这里只是改变获取连接的代码
		Connection conn = local.get();//如果从local中能够得到一个连接对象,那么说明当前线程已经拿过了
		if(conn == null){//如果不能得到一个连接对象,那么说明当前线程没拿过了
			conn = ds.getConnection();
			local.set(conn);
		}
		return conn;
	}
	
	//提供关闭连接的方法
	public static void free(){
		try {
			Connection conn =  local.get();
			if(conn!=null){
				local.remove();
				conn.setAutoCommit(true);//还原我们的连接为自动提交模式,等别人再次拿到这个连接时,就可以默认是自动提交
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public static DataSource getDs() {
		return ds;
	}
	
}

BasicDao. (dbutils)

/*
 * apache工具包,有一个ResultSetHandler接口,结果集处理器的接口
 * ResultSetHandler接口的实现类们:
 * (1)BeanListHandler:结果是一个List<T>
 * (2)BeanHandler:结果是一个Javabean对象
 * (3)MapHandler:结果是一行多列,但是又不是Javabean对象
 * (4)MapListHandler:结果是多行多列,但是又不是Javabean对象
 * (5)ScalarHandler<T>:单个值的封装类型
 * 
 */

public class BasicDAO2 {
	private QueryRunner qr = new QueryRunner(JdbcUtils.getDs());

	//适用于insert,update,delete语句
	public int update(String sql,Object... args) throws Exception{
		return qr.update(sql, args);
	}

	//查询多个Javabean
	public <T> List<T> getList(Class<T> clazz, String sql,Object... args)throws Exception{
		return qr.query(sql, new BeanListHandler<T>(clazz), args);
	}

	//查询一个Javabean,一般跟着主键,唯一键查询
	public <T> T getBean(Class<T> clazz, String sql,Object... args)throws Exception{
		return qr.query(sql, new BeanHandler<T>(clazz), args);
	}

	//例如:查询总记录数,最高工资,最低工资,平均工资,。。。单个值
	public Object queryObject(String sql, Object... args)throws Exception{
		return qr.query(sql, new ScalarHandler<>(), args);
	}

	//查询多行多列,例如:按部门查询平均工资
	public List<Map<String, Object>> queryListMap(String sql, Object... args)throws Exception{
		return qr.query(sql, new MapListHandler(), args);
	}

	//查询一行多列,例如:查询某一个部门的平均工资
	public Map<String, Object> queryMap(String sql, Object... args)throws Exception{
		return qr.query(sql, new MapHandler(), args);
	}
}

impl 实现类

public class UserDAOImpl extends BasicDAO2 implements UserDAO{

    //这个方法根据用户名和密码获取数据库中的记录
    @Override
    public User getUser(User user) {
        try {
            String sql = "SELECT * FROM w WHERE username = ? AND `password` = ?";
            //查询一个对象
            return getBean(User.class, sql, user.getUsername(),user.getPassword());
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public boolean checkUserName(User user) {
        try {
            String sql = "SELECT * FROM users WHERE username = ?";
            //查询一个对象
            User u = getBean(User.class, sql, user.getUsername());
            return u!=null;//如果不为空,说明存在,为true
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void saveUser(User user) {
        try {
            String sql = "INSERT INTO users VALUES(NULL,?,?,?)";
            //查询一个对象
            update(sql, user.getUsername(),user.getPassword(),user.getEmail());
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

}


Test类

public class TestUserDAO {
	UserDAOImpl ud = new UserDAOImpl();

	@Test
	public void test1(){
		//登录
		Scanner input = new Scanner(System.in);
		System.out.println("用户名:");
		String username = input.nextLine();

		System.out.println("密码:");
		String password = input.nextLine();

		User user = new User(username, password);

		User u = ud.getUser(user);
		System.out.println(u);
	}

	@Test
	public void test2(){
		String username = null;
		String password = null;
		//登录
		Scanner input = new Scanner(System.in);
		while(true){
			System.out.println("用户名:");
			username = input.nextLine();
			User user = new User();
			user.setUsername(username);

			//检验这个用户名是否存在
			if(!ud.checkUserName(user)){
				break;
			}else{
				System.out.println("用户名已存在");
			}
		}

		while(true){
			System.out.println("密码:");
			password = input.nextLine();

			System.out.println("确认密码:");
			String confirm = input.nextLine();
			if(password.equals(confirm)){
				break;
			}else{
				System.out.println("两次输入密码要一致");
			}
		}

		System.out.println("邮箱:");
		String email = input.nextLine();

		User u = new User();
		u.setUsername(username);
		u.setPassword(password);
		u.setEmail(email);


		try {
			//注册,添加到数据库中
			ud.saveUser(u);
			System.out.println("注册成功");
		} catch (Exception e) {
			System.out.println("注册失败");
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值