版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/someby/article/details/87953610
目录
在ConfigurationManager.java中添加一个方法
本篇文章将介绍JDBC辅助组件开发。
编写配置文件
my.properties
jdbc.driver=com.mysql.jdbc.Driver; jdbc.datasource.size=10 jdbc.url=jdbc:mysql://localhost:3306/spark_project jdbc.user=root jdbc.password=123456
编写常量借口
Constants.java
package main.xxx.java.constant; /** * 常量借口 */ public interface Constants { /** * 数据库相关的常量 */ String JDBC_DRIVER = "jdbc.driver"; String JDBC_DATASOURCE_SIZE = "jdbc.datasource.size"; String JDBC_URL="jdbc.url"; String JDBC_USER="jdbc.user"; String JDBC_PASSWORD="jdbc.password"; }
编写JDBC辅助组件
JDBCHelper.java
package main.xxx.java.jdbc; import main.xxx.java.conf.ConfigurationManager; import main.xxx.java.constant.Constants; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.LinkedList; import java.util.List; /** * FileName: JDBCHelper * Author: hadoop * Email: [email protected] * Date: 19-2-26 下午10:03 * Description:JDBC辅助组件 * 在正式的项目的代码编写过程中,是完全严格按照大公司的coding标准来的 * 也就是说,在代码中,是不能出现任何hard code(硬编码)的字符 * 比如“张三”、“com.mysql.jdbc.Driver” * 所有这些东西,都需要通过常量来封装和使用 */ public class JDBCHelper { // 第一步:在静态代码块中,直接加载数据库的驱动 // 加载驱动,不是直接简单的,使用com.mysql.jdbc.Driver就可以了 // 之所以说,不要硬编码,他的原因就在于这里 // // com.mysql.jdbc.Driver只代表了MySQL数据库的驱动 // 那么,如果有一天,我们的项目底层的数据库要进行迁移,比如迁移到Oracle // 或者是DB2、SQLServer // 那么,就必须很费劲的在代码中,找,找到硬编码了com.mysql.jdbc.Driver的地方,然后改成 // 其他数据库的驱动类的类名 // 所以正规项目,是不允许硬编码的,那样维护成本很高 // // 通常,我们都是用一个常量接口中的某个常量,来代表一个值 // 然后在这个值改变的时候,只要改变常量接口中的常量对应的值就可以了 // // 项目,要尽量做成可配置的 // 就是说,我们的这个数据库驱动,更进一步,也不只是放在常量接口中就可以了 // 最好的方式,是放在外部的配置文件中,跟代码彻底分离 // 常量接口中,只是包含了这个值对应的key的名字 static { try{ String driver = ConfigurationManager.getProperty(Constants.JDBC_DRIVER); Class.forName(driver); }catch (Exception e){ e.printStackTrace(); } } // 第二步,实现JDBCHelper的单例化 // 为什么要实现代理化呢?因为它的内部要封装一个简单的内部的数据库连接池 // 为了保证数据库连接池有且仅有一份,所以就通过单例的方式 // 保证JDBCHelper只有一个实例,实例中只有一份数据库连接池 private static JDBCHelper instance = null; /** * 获取单例 * @return 单例 */ public static JDBCHelper getInstance(){ if (instance == null){ synchronized (JDBCHelper.class){ if (instance == null){ instance = new JDBCHelper(); } } } return instance; } //数据库链接池 private LinkedList<Connection> datasource = new LinkedList<Connection>(); /** * * 第三步:实现单例的过程中,创建唯一的数据库连接池 * * 私有化构造方法 * * JDBCHelper在整个程序运行声明周期中,只会创建一次实例 * 在这一次创建实例的过程中,就会调用JDBCHelper()构造方法 * 此时,就可以在构造方法中,去创建自己唯一的一个数据库连接池 * */ private JDBCHelper(){ // 首先第一步,获取数据库连接池的大小,就是说,数据库连接池中要放多少个数据库连接 // 这个,可以通过在配置文件中配置的方式,来灵活的设定 int datasourceSize = ConfigurationManager.getInteger(Constants.JDBC_DATASOURCE_SIZE); String url = ConfigurationManager.getProperty(Constants.JDBC_URL); String user = ConfigurationManager.getProperty(Constants.JDBC_USER); String password = ConfigurationManager.getProperty(Constants.JDBC_PASSWORD); // 然后创建指定数量的数据库连接,并放入数据库连接池中 for (int i = 0; i < datasourceSize; i++){ try{ Connection conn = DriverManager.getConnection(url,user,password); datasource.push(conn); }catch(Exception e){ e.printStackTrace(); } } } /** * 第四步,提供获取数据库连接的方法 * 有可能,你去获取的时候,这个时候,连接都被用光了,你暂时获取不到数据库连接 * 所以我们要自己编码实现一个简单的等待机制,去等待获取到数据库连接 * */ public synchronized Connection getConnection(){ while(datasource.size() == 0){ try{ Thread.sleep(10); } catch(Exception e){ e.printStackTrace(); } } return datasource.poll(); } /** * 第五步:开发增删改查的方法 * 1、执行增删改SQL语句的方法 * 2、执行查询SQL语句的方法 * 3、批量执行SQL语句的方法 */ /** * 执行增删改SQL语句 * @param sql * @param params * @return */ public int executeUpdate(String sql,Object[] params){ int rtn = 0; Connection conn = null; PreparedStatement pstmt = null; try{ conn = getConnection(); pstmt = conn.prepareStatement(sql); for (int i = 0; i < params.length; i++){ pstmt.setObject(i+1,params[i]); } rtn = pstmt.executeUpdate(); } catch (Exception e){ e.printStackTrace(); } finally{ if(conn != null){ datasource.push(conn); } } return rtn; } /** * 执行查询SQL语句 * @param sql * @param params * @param callback */ public void executeQuery(String sql,Object[] params,QueryCallback callback){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try{ conn = getConnection(); pstmt = conn.prepareStatement(sql); for (int i = 0; i < params.length;i++){ pstmt.setObject(i+1,params[i]); } rs = pstmt.executeQuery(); callback.process(rs); } catch(Exception e){ e.printStackTrace(); } finally { if(conn != null){ datasource.push(conn); } } } public int[] executeBatch(String sql, List<Object[]> paramList){ int[] rtn = null; Connection conn = null; PreparedStatement pstmt = null; try{ conn = getConnection(); //第一步:使用Connection对象,取消自动提交 conn.setAutoCommit(false); pstmt = conn.prepareStatement(sql); //第二步:使用PreparedStatement.addBatch()方法加入批量的SQL参数 for (Object[] params : paramList){ for (int i = 0; i < params.length; i++){ pstmt.setObject(i+1,params[i]); } pstmt.addBatch(); } //第三步:使用PreparedStatement.executeBatch()方法,执行批量的SQL语句 rtn = pstmt.executeBatch(); //最后一步:使用Connection对象,提交批量的SQL语句 conn.commit(); } catch(Exception e){ e.printStackTrace(); } return rtn; } /** * 静态内部类:查询回调借口 */ public static interface QueryCallback{ /** * 处理查询结果 * @param rs * @throws Exception */ void process(ResultSet rs) throws Exception; } }
JDBCHelperTest.java
package main.xxx.java.test; import main.xxx.java.jdbc.JDBCHelper; import java.sql.ResultSet; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * FileName: JDBCHelperTest * Author: hadoop * Email: [email protected] * Date: 19-2-27 上午10:18 * Description:JDBC辅助组件测试类 */ public class JDBCHelperTest { public static void main(String[] args){ JDBCHelper jdbcHelper = JDBCHelper.getInstance(); //测试普通的增删改语句 testExecuteUpdate(jdbcHelper); //测试查询语句 //testExecuteQuery(jdbcHelper); // 测试批量执行SQL语句 //testExecuteBatch(jdbcHelper); } public static void testExecuteUpdate(JDBCHelper jdbcHelper){ String sql = "insert into test_user(name,age) values(?,?)"; Object[] obj = new Object[]{"Merry",29}; int rtn = jdbcHelper.executeUpdate(sql,obj); System.out.println("result: " + rtn); } public static void testExecuteQuery(JDBCHelper jdbcHelper){ final Map<String,Object> testUser = new HashMap<String,Object>(); //设计一个内部接口QueryCallback // 那么在执行查询语句的时候,我们就可以封装和指定自己的查询结果的处理逻辑 // 封装在一个内部接口的匿名内部类对象中,传入JDBCHelper的方法 // 在方法内部,可以回调我们定义的逻辑,处理查询结果 // 并将查询结果,放入外部的变量中 String sql = "select name ,age from test_user where id=?"; Object[] obj = new Object[]{9}; jdbcHelper.executeQuery(sql, obj, new JDBCHelper.QueryCallback() { @Override public void process(ResultSet rs) throws Exception { if (rs.next()){ String name = rs.getString("name"); int age = rs.getInt("age"); // 匿名内部类的使用,有一个很重要的知识点 // 如果要访问外部类中的一些成员,比如方法内的局部变量 // 那么,必须将局部变量,声明为final类型,才可以访问 // 否则是访问不了的 testUser.put("name",name); testUser.put("age",age); } } }); System.out.println(testUser.get("name")+":"+testUser.get("age")); } public static void testExecuteBatch(JDBCHelper jdbcHelper){ String sql = "insert into test_user(name,age) values(?,?)"; List<Object[]> paramsList = new ArrayList<Object[]>(); paramsList.add(new Object[]{"Mark",12}); paramsList.add(new Object[]{"Bill",25}); jdbcHelper.executeBatch(sql,paramsList); } }
测试结果
在ConfigurationManager.java中添加一个方法
/** * 获取整数类型的配置项 * @param key * @return value */ public static Integer getInteger(String key){ String value = prop.getProperty(key); try{ return Integer.valueOf(value); }catch (Exception e){ e.printStackTrace(); } return 0; } }