zoukankan      html  css  js  c++  java
  • JDBC连接池和DBUtils

    本节内容:

    • JDBC连接池
    • DBUtils

    一、JDBC连接池

    实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采取连接池技术,来共享连接Connection。在程序开始的时候,可以创建几个连接,将连接放入到连接池中。用户使用连接的时候,可以从连接池中进行获取。用完之后,可以将连接归还连接池。

    连接池主要解决的是性能问题。

    1. 连接池概述

    (1)概念

    用池来管理Connection,这样可以重复使用Connection。有了池,我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。池就可以再利用这个Connection对象了。

    (2)规范

    Java为数据库连接池提供了公共的接口,javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便地切换不同厂商的连接池。

    常见的连接池:DBCP、C3P0。还有tomcat自带的JNDI,JNDI使用的概率极低。市场上使用率最高的是C3P0。

    2. 自定义连接池(了解)

    定义一个连接池实现javax.sql.DataSource,使用List集合存放多个连接对象。如果我们需要编写自定义连接池,需要完成以下步骤:

    1. 创建连接池(作为数据源),需要实现接口javax.sql.DataDource。因为我们只使用该接口中getConnection()方法,简化本案例,我们只实现javax.sql.DataDource中的getConnection()方法,而没有实现javax.sql.DataDource中的其他接口
    2. 提供一个集合,用于存放连接,因为移除/添加操作过多,所以选择LinkedList
    3. 本案例在静态代码块中,为连接池初始化5个连接(本案例中初始化连接使用上一篇文章中实现的工具类)
    4. 之后程序如果需要连接,调用实现类的getConnection(),该方法将从连接池(容器List)获得连接。为了保证当前连接只能提供给一个线程使用,所以我们需要将连接先从连接池中移除。
    5. 当用户使用完连接,释放资源时,不执行close()方法,而是将连接添加到连接池中。

    MyDataSource.java

    package cn.itheima.jdbc.DataSource;
    
    import java.io.PrintWriter;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.SQLFeatureNotSupportedException;
    import java.util.LinkedList;
    import java.util.logging.Logger;
    
    import javax.sql.DataSource;
    
    import cn.itheima.jdbc.utils.JDBCUtils_V3;
    
    public class MyDataSource implements DataSource{
    	//1.创建1个容器用于存储Connection对象
    	private static LinkedList<Connection> pool = new LinkedList<Connection>();
    	
    	//2.创建5个连接放到容器中去
    	static{
    		for (int i = 0; i < 5; i++) {
    			Connection conn = JDBCUtils_V3.getConnection();
    			pool.add(conn);
    		}
    	}
    	
    	/**
    	 * 重写获取连接的方法
    	 */
    	@Override
    	public Connection getConnection() throws SQLException {
    		Connection conn = null;
    		//3.使用前先判断
    		if(pool.size()==0){
    			//4.池子里面没有,我们再创建一些
    			for (int i = 0; i < 5; i++) {
    				conn = JDBCUtils_V3.getConnection();
    				pool.add(conn);
    			}
    		}
    		//5.从池子里面获取一个连接对象Connection
    		conn = pool.remove(0);
    		return conn;
    	}
    
    	/**
    	 * 归还连接对象到连接池中去
    	 */
    	public void backConnection(Connection conn){
    		pool.add(conn);
    	}
    
    	@Override
    	public PrintWriter getLogWriter() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void setLogWriter(PrintWriter out) throws SQLException {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void setLoginTimeout(int seconds) throws SQLException {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public int getLoginTimeout() throws SQLException {
    		// TODO Auto-generated method stub
    		return 0;
    	}
    
    	@Override
    	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public <T> T unwrap(Class<T> iface) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public boolean isWrapperFor(Class<?> iface) throws SQLException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public Connection getConnection(String username, String password) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    }

    TestMyDataSource.java

    package cn.itheima.jdbc.test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    
    import javax.sql.DataSource;
    
    import org.junit.Test;
    
    import cn.itheima.jdbc.DataSource.MyDataSource;
    import cn.itheima.jdbc.DataSource.MyDataSource1;
    import cn.itheima.jdbc.utils.JDBCUtils_V3;
    
    public class TestMyDataSource {
    	/**
    	 * 添加用户
    	 * 使用未改造过的connection
    	 */
    	@Test
    	public void testAddUser() {
    		Connection conn = null;
    		PreparedStatement pstmt = null;
    		// 1.创建自定义连接池对象
    		MyDataSource dataSource = new MyDataSource();
    		try {
    			// 2.从池子中获取连接
    			conn = dataSource.getConnection();
    			String sql = "insert into user values(null,?,?)";
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, "吕布");
    			pstmt.setString(2, "貂蝉");
    			int rows = pstmt.executeUpdate();
    			if (rows > 0) {
    				System.out.println("添加成功!");
    			} else {
    				System.out.println("添加失败!");
    			}
    		} catch (Exception e) {
    			throw new RuntimeException(e);
    		} finally {
    			dataSource.backConnection(conn);
    		}
    	}
    	
    }

    JDBCUtils_V3.java

    package cn.itheima.jdbc.utils;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    import java.util.ResourceBundle;
    
    /**
     * 提供获取连接和释放资源的 方法
     * 
     * @author Never Say Never
     * @date 2017年10月29日
     * @version V1.0
     */
    public class JDBCUtils_V3 {
    	private static String driver;
    	private static String url;
    	private static String username;
    	private static String password;
    
    	/**
    	 * 静态代码块加载配置文件信息
    	 */
    	static {
    		try {
    			// 1.通过当前类获取类加载器
    			ClassLoader classLoader = JDBCUtils_V3.class.getClassLoader();
    			// 2.通过类加载器的方法获得一个输入流
    			InputStream is = classLoader.getResourceAsStream("db.properties");
    			// 3.创建一个properties对象
    			Properties props = new Properties();
    			// 4.加载输入流
    			props.load(is);
    			// 5.获取相关参数的值
    			driver = props.getProperty("driver");
    			url = props.getProperty("url");
    			username = props.getProperty("username");
    			password = props.getProperty("password");
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    	/**
    	 * 获取连接方法
    	 * 
    	 * @return
    	 */
    	public static Connection getConnection() {
    		Connection conn = null;
    		try {
    			Class.forName(driver);
    			conn = DriverManager.getConnection(url, username, password);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return conn;
    	}
    
    	/**
    	 * 释放资源方法
    	 * 
    	 * @param conn
    	 * @param pstmt
    	 * @param rs
    	 */
    	public static void release(Connection conn, PreparedStatement pstmt, ResultSet rs) {
    		if (rs != null) {
    			try {
    				rs.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    		if (pstmt != null) {
    			try {
    				pstmt.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    		if (conn != null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    
    	}
    }

    3. 自定义连接池(方法增强)

    上面的自定义连接池示例中存在严重问题,用户调用getConnection()获得连接后,必须使用backConnection(conn)方法进行连接的归还,如果用户调用conn.close()将连接真正的释放,连接池中将出现无连接可用。

    我们希望用户即使调用了close()方法,连接仍归还给连接池。我们需要对close()方法进行增强,从而实现将连接归还给连接池的功能。

    (1)方法增强的方式

    • 继承:子类继承父类,将父类的方法进行重写,从而进行增强
      • 使用前提:必须有父类,且存在继承关系。
    • 装饰者设计模式,此设计模式专门用于增强方法
      • 使用前提:必须有接口
      • 缺点:需要将接口的所有方法都实现
    • 动态代理:在运行时动态的创建代理类,完成增强操作,与装饰者类似。
      • 使用前提:必须有接口
      • 难点:需要反射技术
    • 字节码增强,运行时创建目标类子类,从而进行增强
      • 常见第三方框架:cglib、javassist等

    (2)装饰者设计模式

    设计模式:专门为解决某一类问题,而编写的固定格式的代码。

    装饰者固定结构:接口A,已知实现类C,需要装饰者创建代理类B

    1. 创建类B,并实现接口A
    2. 提供类B的构造方法,参数类型A,用于接收A接口的其他实现类(C)
    3. 给类B添加类型为A成员变量,用于存放A接口的其他实现类
    4. 增强需要的方法
    5. 实现不需要增强的方法,方法里调用成员变量存放的其他实现类对应的方法

    MyConnection.java

    package cn.itheima.jdbc.DataSource;
    
    import java.sql.Array;
    import java.sql.Blob;
    import java.sql.CallableStatement;
    import java.sql.Clob;
    import java.sql.Connection;
    import java.sql.DatabaseMetaData;
    import java.sql.NClob;
    import java.sql.PreparedStatement;
    import java.sql.SQLClientInfoException;
    import java.sql.SQLException;
    import java.sql.SQLWarning;
    import java.sql.SQLXML;
    import java.sql.Savepoint;
    import java.sql.Statement;
    import java.sql.Struct;
    import java.util.LinkedList;
    import java.util.Map;
    import java.util.Properties;
    import java.util.concurrent.Executor;
    
    //1.实现同一个接口Connection
    public class MyConnection implements Connection {
    	//3.定义一个变量
    	private Connection conn;
    	
    	private LinkedList<Connection> pool;
    	
    	// 2.编写一个构造方法(参数使用了面相对象的多态特性)
    	public MyConnection(Connection conn,LinkedList<Connection> pool) {
    		this.conn=conn;
    		this.pool=pool;
    	}
    	
    	//4.书写需要增强的方法
    	@Override
    	public void close() throws SQLException {
    		pool.add(conn);
    	}
    
    	/**
    	 * 此方法必须覆盖!否则会出现空指针异常!!!
    	 */
    	@Override
    	public PreparedStatement prepareStatement(String sql) throws SQLException {
    		return conn.prepareStatement(sql);
    	}
    	
    	@Override
    	public <T> T unwrap(Class<T> iface) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public boolean isWrapperFor(Class<?> iface) throws SQLException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public Statement createStatement() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public CallableStatement prepareCall(String sql) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public String nativeSQL(String sql) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void setAutoCommit(boolean autoCommit) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public boolean getAutoCommit() throws SQLException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public void commit() throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public void rollback() throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public boolean isClosed() throws SQLException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public DatabaseMetaData getMetaData() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void setReadOnly(boolean readOnly) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public boolean isReadOnly() throws SQLException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public void setCatalog(String catalog) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public String getCatalog() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void setTransactionIsolation(int level) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public int getTransactionIsolation() throws SQLException {
    		// TODO Auto-generated method stub
    		return 0;
    	}
    
    	@Override
    	public SQLWarning getWarnings() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void clearWarnings() throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
    			throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Map<String, Class<?>> getTypeMap() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public void setHoldability(int holdability) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public int getHoldability() throws SQLException {
    		// TODO Auto-generated method stub
    		return 0;
    	}
    
    	@Override
    	public Savepoint setSavepoint() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Savepoint setSavepoint(String name) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void rollback(Savepoint savepoint) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public void releaseSavepoint(Savepoint savepoint) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
    			throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
    			int resultSetHoldability) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
    			int resultSetHoldability) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Clob createClob() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Blob createBlob() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public NClob createNClob() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public SQLXML createSQLXML() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public boolean isValid(int timeout) throws SQLException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public void setClientInfo(String name, String value) throws SQLClientInfoException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public void setClientInfo(Properties properties) throws SQLClientInfoException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public String getClientInfo(String name) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Properties getClientInfo() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void setSchema(String schema) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public String getSchema() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void abort(Executor executor) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public int getNetworkTimeout() throws SQLException {
    		// TODO Auto-generated method stub
    		return 0;
    	}
    
    }

    MyDataSource1.java

    package cn.itheima.jdbc.DataSource;
    
    import java.io.PrintWriter;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.SQLFeatureNotSupportedException;
    import java.util.LinkedList;
    import java.util.logging.Logger;
    
    import javax.sql.DataSource;
    
    import cn.itheima.jdbc.utils.JDBCUtils_V3;
    
    public class MyDataSource1 implements DataSource{
    	//1.创建1个容器用于存储Connection对象
    	private static LinkedList<Connection> pool = new LinkedList<Connection>();
    	
    	//2.创建5个连接放到容器中去
    	static{
    		for (int i = 0; i < 5; i++) {
    			Connection conn = JDBCUtils_V3.getConnection();
    			//放入池子中connection对象已经经过改造了
    			MyConnection myconn = new MyConnection(conn, pool);
    			pool.add(myconn);
    		}
    	}
    	
    	/**
    	 * 重写获取连接的方法
    	 */
    	@Override
    	public Connection getConnection() throws SQLException {
    		Connection conn = null;
    		//3.使用前先判断
    		if(pool.size()==0){
    			//4.池子里面没有,我们再创建一些
    			for (int i = 0; i < 5; i++) {
    				conn = JDBCUtils_V3.getConnection();
    				//放入池子中connection对象已经经过改造了
    				MyConnection myconn = new MyConnection(conn, pool);
    				pool.add(myconn);
    			}
    		}
    		//5.从池子里面获取一个连接对象Connection
    		conn = pool.remove(0);
    		return conn;
    	}
    
    	/**
    	 * 归还连接对象到连接池中去
    	 */
    	public void backConnection(Connection conn){
    		pool.add(conn);
    	}
    
    	@Override
    	public PrintWriter getLogWriter() throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public void setLogWriter(PrintWriter out) throws SQLException {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void setLoginTimeout(int seconds) throws SQLException {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public int getLoginTimeout() throws SQLException {
    		// TODO Auto-generated method stub
    		return 0;
    	}
    
    	@Override
    	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public <T> T unwrap(Class<T> iface) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public boolean isWrapperFor(Class<?> iface) throws SQLException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public Connection getConnection(String username, String password) throws SQLException {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    }
    

    TestMyDataSource.java

    package cn.itheima.jdbc.test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    
    import javax.sql.DataSource;
    
    import org.junit.Test;
    
    import cn.itheima.jdbc.DataSource.MyDataSource;
    import cn.itheima.jdbc.DataSource.MyDataSource1;
    import cn.itheima.jdbc.utils.JDBCUtils_V3;
    
    public class TestMyDataSource {
    	/**
    	 * 添加用户
    	 * 使用未改造过的connection
    	 */
    	@Test
    	public void testAddUser() {
    		Connection conn = null;
    		PreparedStatement pstmt = null;
    		// 1.创建自定义连接池对象
    		MyDataSource dataSource = new MyDataSource();
    		try {
    			// 2.从池子中获取连接
    			conn = dataSource.getConnection();
    			String sql = "insert into user values(null,?,?)";
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, "吕布");
    			pstmt.setString(2, "貂蝉");
    			int rows = pstmt.executeUpdate();
    			if (rows > 0) {
    				System.out.println("添加成功!");
    			} else {
    				System.out.println("添加失败!");
    			}
    		} catch (Exception e) {
    			throw new RuntimeException(e);
    		} finally {
    			dataSource.backConnection(conn);
    		}
    	}
    	
    	
    	/**
    	 * 添加用户
    	 * 使用改造过的connection
    	 */
    	@Test
    	public void testAddUser1() {
    		Connection conn = null;
    		PreparedStatement pstmt = null;
    		// 1.创建自定义连接池对象
    		DataSource dataSource = new MyDataSource1();
    		try {
    			// 2.从池子中获取连接
    			conn = dataSource.getConnection();
    			String sql = "insert into user values(null,?,?)";
    			//3.必须在自定义的connection类中重写prepareStatement(sql)方法
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, "吕布1");
    			pstmt.setString(2, "貂蝉1");
    			int rows = pstmt.executeUpdate();
    			if (rows > 0) {
    				System.out.println("添加成功!");
    			} else {
    				System.out.println("添加失败!");
    			}
    		} catch (Exception e) {
    			throw new RuntimeException(e);
    		} finally {
    			JDBCUtils_V3.release(conn, pstmt, null);
    		}
    	}
    }

    JDBCUtils_V3.java

    package cn.itheima.jdbc.utils;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    import java.util.ResourceBundle;
    
    /**
     * 提供获取连接和释放资源的 方法
     * 
     * @author Never Say Never
     * @date 2017年10月29日
     * @version V1.0
     */
    public class JDBCUtils_V3 {
    	private static String driver;
    	private static String url;
    	private static String username;
    	private static String password;
    
    	/**
    	 * 静态代码块加载配置文件信息
    	 */
    	static {
    		try {
    			// 1.通过当前类获取类加载器
    			ClassLoader classLoader = JDBCUtils_V3.class.getClassLoader();
    			// 2.通过类加载器的方法获得一个输入流
    			InputStream is = classLoader.getResourceAsStream("db.properties");
    			// 3.创建一个properties对象
    			Properties props = new Properties();
    			// 4.加载输入流
    			props.load(is);
    			// 5.获取相关参数的值
    			driver = props.getProperty("driver");
    			url = props.getProperty("url");
    			username = props.getProperty("username");
    			password = props.getProperty("password");
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    	/**
    	 * 获取连接方法
    	 * 
    	 * @return
    	 */
    	public static Connection getConnection() {
    		Connection conn = null;
    		try {
    			Class.forName(driver);
    			conn = DriverManager.getConnection(url, username, password);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return conn;
    	}
    
    	/**
    	 * 释放资源方法
    	 * 
    	 * @param conn
    	 * @param pstmt
    	 * @param rs
    	 */
    	public static void release(Connection conn, PreparedStatement pstmt, ResultSet rs) {
    		if (rs != null) {
    			try {
    				rs.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    		if (pstmt != null) {
    			try {
    				pstmt.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    		if (conn != null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    
    	}
    }

    4. C3P0连接池

    C3P0开源免费的连接池。目前使用它的开源项目有:Spring、Hibernate等。使用第三方工具需要导入jar包,c3p0使用时可以添加配置文件c3p0-config.xml(或者c3p0.properties,大部分使用c3p0-config.xml),也可以不添加配置文件。它有两种使用方式,但是多数情况下都是用需要配置文件的那种方式。

    (1)导入jar包

    如果使用的是0.9.2版本,需要导入两个jar包。

    如果使用的是0.9.1版本,只需要导入c3p0-0.9.1.2.jar。

    (2)配置文件

    • 配置文件名称:c3p0-config.xml(固定)
    • 配置文件位置:src(类路径)
    • 配置文件内容:命名配置
    <c3p0-config>
    
        <named-config name="itheima">
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql:///web08</property>
            <property name="user">root</property>
            <property name="password">123456</property>
        </named-config>
    
    </c3p0-config>
    命名配置
    • 配置文件内容:默认配置
    <c3p0-config>
      <default-config>
        <property name="automaticTestTable">con_test</property>
        <property name="checkoutTimeout">30000</property>
        <property name="idleConnectionTestPeriod">30</property>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    
      </default-config>
    </c3p0-config>
    默认配置

    (3)示例

    c3p0提供核心工具类:ComboPooledDataSource,如果要使用连接池,必须创建该类的实例对象。

    • new ComboPooledDataSource("itcast");  使用配置文件“命名配置”
      • <name-config name="itcast">
    • new ComboPooledDataSource();  使用配置文件“默认配置”
      • <default-config>
    <?xml version="1.0" encoding="UTF-8"?>
    <c3p0-config>
    
        <default-config>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql:///web08</property>
            <property name="user">root</property>
            <property name="password">123456</property>
            <property name="initialPoolSize">5</property>
            <property name="maxPoolSize">20</property>
        </default-config>
    
        <named-config name="itheima">
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql:///web08</property>
            <property name="user">root</property>
            <property name="password">123456</property>
        </named-config>
    
    </c3p0-config>
    c3p0-config.xml
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    
    import org.junit.Test;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import cn.itheima.jdbc.utils.JDBCUtils_V3;
    
    public class TestC3P0 {
        @Test
        public void testAddUser() {
            Connection conn = null;
            PreparedStatement pstmt = null;
            // 1.创建自定义连接池对象
            ComboPooledDataSource dataSource = new ComboPooledDataSource();// 加载默认的配置
            // ComboPooledDataSource dataSource = new ComboPooledDataSource("itheima");//加载有名称的配置
            
            try {
                // 2.从池子中获取连接
                conn = dataSource.getConnection();
                String sql = "insert into tbl_user values(null,?,?)";
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, "吕布2");
                pstmt.setString(2, "貂蝉2");
                int rows = pstmt.executeUpdate();
                if (rows > 0) {
                    System.out.println("添加成功!");
                } else {
                    System.out.println("添加失败!");
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                JDBCUtils_V3.release(conn, pstmt, null);
            }
        }
    }
    TestC3P0.java
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    import java.util.ResourceBundle;
    
    /**
     * 提供获取连接和释放资源的 方法
     * 
     * @author Never Say Never
     * @date 2017年10月29日
     * @version V1.0
     */
    public class JDBCUtils_V3 {
        private static String driver;
        private static String url;
        private static String username;
        private static String password;
    
        /**
         * 静态代码块加载配置文件信息
         */
        static {
            try {
                // 1.通过当前类获取类加载器
                ClassLoader classLoader = JDBCUtils_V3.class.getClassLoader();
                // 2.通过类加载器的方法获得一个输入流
                InputStream is = classLoader.getResourceAsStream("db.properties");
                // 3.创建一个properties对象
                Properties props = new Properties();
                // 4.加载输入流
                props.load(is);
                // 5.获取相关参数的值
                driver = props.getProperty("driver");
                url = props.getProperty("url");
                username = props.getProperty("username");
                password = props.getProperty("password");
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        /**
         * 获取连接方法
         * 
         * @return
         */
        public static Connection getConnection() {
            Connection conn = null;
            try {
                Class.forName(driver);
                conn = DriverManager.getConnection(url, username, password);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return conn;
        }
    
        /**
         * 释放资源方法
         * 
         * @param conn
         * @param pstmt
         * @param rs
         */
        public static void release(Connection conn, PreparedStatement pstmt, ResultSet rs) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    JDBCUtils_V3.java

    可以写一个工具类,修改下相关代码:

    import java.sql.Connection;
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    public class C3P0Utils {
        private static ComboPooledDataSource dataSource = new ComboPooledDataSource("itheima");
    
        public static DataSource getDataSource() {
            return dataSource;
        }
    
        public static Connection getConnection() {
            try {
                return dataSource.getConnection();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
    C3P0Utils.java
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    
    import org.junit.Test;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import cn.itheima.jdbc.utils.C3P0Utils;
    import cn.itheima.jdbc.utils.JDBCUtils_V3;
    
    public class TestC3P0 {
        @Test
        public void testAddUser1() {
            Connection conn = null;
            PreparedStatement pstmt = null;
            try {
                // 2.从池子中获取连接
                conn = C3P0Utils.getConnection();
                String sql = "insert into tbl_user values(null,?,?)";
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, "吕布3");
                pstmt.setString(2, "貂蝉3");
                int rows = pstmt.executeUpdate();
                if (rows > 0) {
                    System.out.println("添加成功!");
                } else {
                    System.out.println("添加失败!");
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                JDBCUtils_V3.release(conn, pstmt, null);
            }
        }
    
    }
    TestC3P0.java

    5. DBCP连接池

    DBCP也是一个开源的连接池,是Apache上的一个java连接池项目,在企业开发中也比较常见,tomcat内置的连接池。

    (1)导入jar包

    commons-dbcp-1.4.jar和commons-pool-1.5.6.jar

    (2)配置文件

    • 配置文件名称:*.properties
    • 配置文件位置:任意,建议src(classpath/类路径)
    • 配置文件内容:properties不能写中文,不支持在STS(Eclipse的一个变种)中修改,必须使用记事本修改内容,否则中文注释就乱码了
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/web08?useUnicode=true&characterEncoding=utf8
    username=root
    password=123456
    db.properties
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.Properties;
    
    import javax.sql.DataSource;
    
    import org.apache.commons.dbcp.BasicDataSourceFactory;
    
    public class DBCPUtils {
        private static DataSource dataSource;
        static{
            try {
                //1.加载找properties文件输入流
                InputStream is = DBCPUtils.class.getClassLoader().getResourceAsStream("db.properties");
                //2.加载输入流
                Properties props = new Properties();
                props.load(is);
                //3.创建数据源
                dataSource = BasicDataSourceFactory.createDataSource(props);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        
        public static DataSource getDataSource(){
            return dataSource;
        }
        
        public static Connection getConnection(){
            try {
                return dataSource.getConnection();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
    DBCPUtils.java
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    
    import org.junit.Test;
    
    import cn.itheima.jdbc.utils.DBCPUtils;
    
    public class TestDBCP {
    
        @Test
        public void testUpdateUserById(){
            Connection conn = null;
            PreparedStatement pstmt = null;
            try {
                conn = DBCPUtils.getConnection();
                String sql ="update tbl_user set upassword=? where uid=?";
                pstmt= conn.prepareStatement(sql);
                pstmt.setString(1, "柳岩");
                pstmt.setInt(2, 20);
                int rows = pstmt.executeUpdate();
                if(rows>0){
                    System.out.println("更新成功!");
                }else{
                    System.out.println("更新失败!");
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    TestDBCP.java

    二、DBUtils

    如果在某些项目中,不使用框架,只使用JDBC开发,我们会发现冗余代码过多:

    为了简化JDBC开发,我们采用apache commons组件的一个成员:DBUtils。

    DBUtils就是JDBC的简化开发工具包。需要使用的技术:连接池(只用到里面的获得连接),SQL语句并没有变少以及设置sql语句中的参数。

    1. JavaBean组件

    JavaBean就是一个类,在开发中常用语封装数据。具有如下特性:

    1. 需要实现接口:java.io.Serializable,通常偷懒省略了。
    2. 提供私有字段:private 类型 字段名;
    3. 提供getter/setter方法
    4. 提供无参构造

    一般将JavaBean类放到domain包或model包里。

    2. DBUtils介绍

    (1)概述

    DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。在不使用框架的情况下,使用DBUtils的概率非常大。

    DBUtils三个核心功能介绍:

    • QueryRunner类,提供对sql语句操作的API
    • ResultSetHandler接口,用于定义select操作后,怎样封装结果集
    • DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

    (2)QueryRunner核心类

    • QueryRunner(Database ds),提供了数据源(连接池),DBUtils底层自动维护connection
    • update(String sql, Object... params),执行更新数据。(增、删、改)
    • query(String sql, ResultSetHandler<T> rsh, Object... params),执行查询

    (3)ResultSetHandler结果处理集类

    我们知道在执行select语句之后得到的是ResultSet,然后我们还需要对ResultSet进行转换,得到最终我们想要的数据。你可能希望把ResultSet的数据放到一个List中,也可能想把数据放到一个Map中,或是一个Bean中。

    DBUtils提供了一个接口ResultSetHandler,它就是用来ResultSet转换成目标类型的工具。你可以自己去实现这个接口,把ResultSet转换成你想要的类型。

    DBUtils提供了很多个ResultSetHandler接口的实现,这些实现已经基本够用了,我们通常不用自己去实现ResultSet接口了。

    • MapHandler:单行处理器!把结果集转换成Map<String,Object>,其中列名为键
    • MapListHandler:多行处理器!把结果集转换成List<Map<String,Object>>;
    • BeanHandler:单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型;
    • BeanListHandler:多行处理器!把结果集转换成List<Bean>;
    • ColumnListHandler:多行单列处理器!把结果集转换成List<Object>,使用ColumnListHandler时需要指定某一列的名称或编号,例如:new ColumListHandler(“name”)表示把name列的数据放到List中。
    • ScalarHandler:单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select count(*) from tab_student。
    ArrayHandler 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值
    ArrayListHangler 将结果集中的第一条记录封装到一个Object[]数组中,将这些数组在封装到List集合中
    BeanHandler 将结果集中的每一条记录封装到一个指定的javaBean中
    BeanListHandler 将结果集中每一条记录封装到指定的javaBean中,将这些JavaBean在封装到List集合中
    ColumnListHandler 将结果集中指定的列的字段值,封装到一个List集合中
    KeyedHandler 将结果集中每一条记录封装到Map<String,Object>,在将这个map结婚作为另一个Map的value,另一个Map集合的key是指定的字段的名称
    MapHandler 将结果集中第一条记录封装到Map<String,Object>集合中,key就是字段名称,value就是字段值
    MapListHandler 将结果集中每一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值,在将这些Map封装到List集合中
    ScalarHandler 它用于单数据。例如select count(*) from table 操作

    Map处理器:
      每一条记录作为一个Map,Map的key是字段名称。

    Bean处理器 :
      必须搞一个javaBean。


    Column处理器:


    Scalar处理器:

     

    (4)DbUtils工具类

    • closeQuietly(Connection conn)  关闭连接,如果有异常try后不抛
    • commitAndCloseQuietly(Connection conn)  提交并关闭连接
    • rollbackAndCloseQuietly(Connection conn)  回滚并关闭连接

    3. 示例:使用DBUtils完成增删改查操作

    public class User {
        private int uid;
        private String uname;
        private String upassword;
    
        public User() {
        }
    
        public int getUid() {
            return uid;
        }
    
        public void setUid(int uid) {
            this.uid = uid;
        }
    
        public String getUname() {
            return uname;
        }
    
        public void setUname(String uname) {
            this.uname = uname;
        }
    
        public String getUpassword() {
            return upassword;
        }
    
        public void setUpassword(String upassword) {
            this.upassword = upassword;
        }
    
    }
    User.java
    import java.sql.Connection;
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    public class C3P0Utils {
        private static ComboPooledDataSource dataSource = new ComboPooledDataSource("itheima");
    
        public static DataSource getDataSource() {
            return dataSource;
        }
    
        public static Connection getConnection() {
            try {
                return dataSource.getConnection();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
    C3P0Utils.java
    import java.sql.SQLException;
    
    import org.apache.commons.dbutils.QueryRunner;
    import org.junit.Test;
    
    import cn.itheima.jdbc.utils.C3P0Utils;
    
    /**
     * 测试DBUtils工具类的增删改操作
     * 
     * @author Never Say Never
     * @date 2017年10月31日
     * @version V1.0
     */
    public class TestDBUtils1 {
    
        /**
         * 添加所有用户方法
         */
        @Test
        public void testAddUser() {
            try {
                // 1.创建核心类QueryRunner
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                // 2.编写SQL语句
                String sql = "insert into user values(null,?,?)";
                // 3.为占位符设置值
                Object[] params = { "余淮", "耿耿" };
                // 4.执行添加操作
                int rows = qr.update(sql, params);
                if (rows > 0) {
                    System.out.println("添加成功!");
                } else {
                    System.out.println("添加失败!");
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        /**
         * 根据id修改用户方法
         * 
         */
        @Test
        public void testUpdateUserById() {
            try {
                // 1.创建核心类QueryRunner
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                // 2.编写SQL语句
                String sql = "update user set upassword=? where uid=?";
                // 3.为站位符设置值
                Object[] params = { "xxx", 21 };
                // 4.执行添加操作
                int rows = qr.update(sql, params);
                if (rows > 0) {
                    System.out.println("修改成功!");
                } else {
                    System.out.println("修改失败!");
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        /**
         * 根据id删除用户方法
         */
        @Test
        public void testDeleteUserById() {
            try {
                // 1.创建核心类QueryRunner
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                // 2.编写SQL语句
                String sql = "delete from user where uid=?";
                // 3.为站位符设置值
                Object[] params = {19};
                // 4.执行添加操作
                int rows = qr.update(sql, params);
                if (rows > 0) {
                    System.out.println("删除成功!");
                } else {
                    System.out.println("删除失败!");
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    TestDBUtils1.java --添加、删除、更新
    import java.sql.SQLException;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanHandler;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    import org.apache.commons.dbutils.handlers.ColumnListHandler;
    import org.apache.commons.dbutils.handlers.MapListHandler;
    import org.apache.commons.dbutils.handlers.ScalarHandler;
    import org.junit.Test;
    
    import cn.itheima.domain.User;
    import cn.itheima.jdbc.utils.C3P0Utils;
    
    /**
     * 测试DBUtils查询操作
     * 
     * @author Never Say Never
     * @date 2017年10月31日
     * @version V1.0
     */
    public class TestDBUtils2 {
    
        /*
         * 查询所有用户方法
         */
        @Test
        public void testQueryAll() {
            try {
                // 1.获取核心类queryRunner
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                // 2.编写sql语句
                String sql = "select * from user";
                // 3.执行查询操作
                List<User> users = qr.query(sql, new BeanListHandler<User>(User.class));
                // 4.对结果集集合进行遍历
                for (User user : users) {
                    System.out.println(user.getUname() + " : " + user.getUpassword());
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        
        /*
         * 根据id查询用户方法
         */
        @Test
        public void testQueryUserById() {
            try {
                // 1.获取核心类queryRunner
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                // 2.编写sql语句
                String sql = "select * from user where uid=?";
                //3.为占位符设置值
                Object[] params = {21};
                // 4.执行查询操作
                User user = qr.query(sql, new BeanHandler<User>(User.class), params);
                System.out.println(user.getUname() + " : " + user.getUpassword());
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        
        /*
         * 根据所有用户的总个数
         */
        @Test
        public void testQueryCount() {
            try {
                // 1.获取核心类queryRunner
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                // 2.编写sql语句
                String sql = "select count(*) from tbl_user";
                // 4.执行查询操作
                Long count = (Long) qr.query(sql, new ScalarHandler());
                System.out.println(count);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        
        /*
         * 查询所有用户方法
         */
        @Test
        public void testQueryAll1() {
            try {
                // 1.获取核心类queryRunner
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                // 2.编写sql语句
                String sql = "select * from user";
                // 3.执行查询操作
                List<Map<String, Object>> list = qr.query(sql, new MapListHandler());
                // 4.对结果集集合进行遍历
                for (Map<String, Object> map : list) {
                    System.out.println(map);
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        
        /*
         * 查询所有用户方法
         */
        @Test
        public void testQueryAll2() {
            try {
                // 1.获取核心类queryRunner
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                // 2.编写sql语句
                String sql = "select * from user";
                // 3.执行查询操作
                List<Object> list = qr.query(sql, new ColumnListHandler("uname"));
                // 4.对结果集集合进行遍历
                for (Object object : list) {
                    System.out.println(object);
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
    TestDBUtils2.java --查询操作

    【注意】:DBUtils在创建QueryRunner时传入dataSource对象,每次在执行完之后都会自动关闭Connection连接对象。(就相当于把conn交给dbutils管理了,他会帮我们关掉)

    如果没有传入dataSource的话,需要手动关闭。

  • 相关阅读:
    node
    github
    [模块] pdf转图片-pdf2image
    python 15 自定义模块 随机数 时间模块
    python 14 装饰器
    python 13 内置函数II 匿名函数 闭包
    python 12 生成器 列表推导式 内置函数I
    python 11 函数名 迭代器
    python 10 形参角度 名称空间 加载顺序
    python 09 函数参数初识
  • 原文地址:https://www.cnblogs.com/zhaojiankai/p/7891521.html
Copyright © 2011-2022 走看看