JDBCUtil :
package com.macw.util; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.sql.DataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; /** * @author 超伟 * @2019年5月29日 下午3:48:26 * @博客:https://blog.csdn.net/MacWx */ public class JdbcUtil { public static DataSource ds; public static final ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); // 把流操作提取到静态代码块里面。 static { InputStream in = null; // 创建连接池对象 try { // 创建出Properties对象 Properties prop = new Properties(); in = JdbcUtil.class.getResourceAsStream("/druid.properties"); // 读取文件中的数据 prop.load(in); // 创建连接池对象 ds = DruidDataSourceFactory.createDataSource(prop); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); throw new RuntimeException(e); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); throw new RuntimeException(e); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /** * * @return */ public static Connection getConnection() { //优先从线程中获取连接 Connection conn = tl.get(); // 如果没有拿到这个线程,就说明是业务类在调用 //如果从线程中获取失败,则再新建和数据库的连接 if (conn == null) { try { // 用数据库连接池来获取数据库连接 conn = ds.getConnection(); tl.set(conn); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); throw new RuntimeException(e); } } return conn; } /** * * @param conn * @param ps * @param rs */ public static void toClose(Connection conn, PreparedStatement ps, ResultSet rs) { try { // 代码不用改,但是含义改变了,把这个连接归还给数据库连接池 // //为了代码的健壮性,需要增加非空判断 if (rs != null) { rs.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 释放ps对象,关闭资源的时候需要注意顺序,后创建的对象,要先关闭。 try { if (ps != null) { ps.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if (conn != null) { conn.close(); //关闭连接,要从线程中移除 tl.remove(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 使用jdbc对于增删改方法的封装 * * 对于增删改方法,仍有大部分的冗余代码,但在这些冗余代码中又有一些是不同的 * 例如sql语句,以及传入的参数,所以可把相同的代码封装,不同的代码抽取 * 这只是代码的简化,并不是程序的优化 * * * @param sql 对于sql语句的抽取 * @param obj 可变长参数 * 可变长参数必须是最后一个形参,也只能有一个这样的形参 * 在该方法内部,将obj当成一个数组使用。 * @throws SQLException */ public static void update(String sql,Object...obj) throws SQLException{ Connection conn = null; PreparedStatement ps = null; try{ //调用本类中的获取连接方法 conn = getConnection(); ps = conn.prepareStatement(sql); //再判断传入的参数是否为空 if (obj != null) { //如果不为空则挨个赋值 for (int i = 0; i < obj.length; i++) { ps.setObject(i+1, obj[i]); } } ps.executeUpdate(); //这里不用catch异常是因为要在dao中去处理 }finally{ //这里的conn连接不要关,在services层中去关闭!在services中处理事务! toClose(null, ps, null); } } /* * 反射: * * 什么是类对象和类的对象? * Student s = new Student(); s是类的对象,是某一个类创建出来的对象,这个类是Student //1.在运行期加载一个类到虚拟机中 Class c = Class.forName(“com.macw.Student”); //c就是Student的类对象 //2. 通过反射创建Student类的对象 Object o = c.newInstance(); //o 是Student类的对象 //3.获取Student类指定的方法 和 获取所有的方法 Method method = c.getMethod(“方法名”,形参类型); //method指某一个方法 method.invoke(对象,实参); //动态调用该方法 Method[] methods = c.getMethods(); //methods指类中所有的方法 * */ /** * 查询多条 * <T> 是用来规范泛型的, * @throws SQLException * @throws IllegalAccessException * @throws InstantiationException * @throws InvocationTargetException * @throws IllegalArgumentException * */ public static <T> List<T> select(String sql,Class<T> clz,Object...obj) throws SQLException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<T> list = null; try { conn = getConnection(); // 1,预加载SQL语句 ps = conn.prepareStatement(sql); // 2,设置占位符 if (obj != null) { for (int i = 0; i < obj.length; i++) { ps.setObject(i+1, obj[i]); } } // 3,执行SQL语句 rs = ps.executeQuery(); // 获取查询结果集中的元数据 // 元数据可以理解为查询结果中的列名 ResultSetMetaData md = rs.getMetaData(); // 获取查询到的列的个数; int columnCount = md.getColumnCount(); // System.out.println(columnCount); list = new ArrayList<>(); T t = null; while(rs.next()){//while每循环一次,代表一行数据。 //clz代表实体类对象, // 创建实体类的对象 t = clz.newInstance(); for (int i = 0; i < columnCount; i++) {//一行数据有几列就循环几次 // 根据下标获取列名 String columnName = md.getColumnName(i+1); // 再根据列名获取对应列的值 Object value = rs.getObject(columnName); // 要将每一列的值赋值给t对象的属性,要要求表中的列名和实体类属性名必须一致! // 这是通过字符串拼接成 setName();方法 String methodName = "set" + columnName.substring(0, 1).toUpperCase()+ columnName.substring(1).toLowerCase(); // 获取当前实体类中传递过来的所有方法 Method[] methods = clz.getMethods(); // 进行for循环获取所有的set方法 for (Method m : methods) { // 判断所有的方法中有没有查询结果列名拼成的set方法 // 获取实体类中所有的方法名用:m.getName()方法 if (m.getName().equals(methodName)) { // Oracle中的number类型对应java中的java.math.BigDecimal类型 /** * rs.getInt("id"); 那么number类型就被转换成了int类型; * rs.getDouble("price");那么number类型就转换成了double类型 * rs.getObject("列名"); 那么返回的实际类型是java.math.BigDecimal; * Bigdecimal 没有精度损失,多用户银行等的金融计算; */ // value如果是Bigdecimal类型,意味着在数据库中是number类型 // 所以需要强转成int或者double类型 if (value == null) {//如果有空的数据,不再强转直接跳过 continue; } else if (value instanceof BigDecimal) { Class<?> c2 = m.getParameterTypes()[0]; if (c2.getName().equals("java.lang.Integer")) { value = ((BigDecimal)value).intValue(); }else if(c2.getName().equals("double")){ value = ((BigDecimal)value).doubleValue(); } else if(c2.getName().equals("int")){ value = ((BigDecimal)value).intValue(); } } //动态执行set方法 m.invoke(t, value); } } } //while每循环一次,就创建一个实体类对象,给对象的属性赋值, // 然后将对象存储到list集合中 list.add(t); } }finally{ toClose(null, ps, rs); } return list; } }jdbcUtil工具类的使用: 如下所示:
查询方法:
public User selectByNameAndPwd(String username, String password) { // TODO Auto-generated method stub String sql = "select * from t_user where username = ? and password = ?"; User u = null; try { List<User> list = JdbcUtil.select(sql, User.class,username,password); for (User user : list) { u = new User(user.getUser_id(),user.getUsername(),user.getPassword()); } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return u; } }增删改方法: 增删改都是一样的,都是调用JdbcUtil的update方法,因为增删改执行的方法都是没有返回值的,所以可以统一处理! 简化jdbc重复代码!
public void updatePwd(int id,String newPassword) { // TODO Auto-generated method stub try { String sql = "update t_user set password = ? where user_id = ?"; JdbcUtil.update(sql, newPassword,id); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } }