优化JDBC封装

Posted 遗风遗风丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了优化JDBC封装相关的知识,希望对你有一定的参考价值。

可重用性较强的JDBC封装

以下为代码,注释中写了主要思想

主类

com.util.JDBCUtil.java

  1 package com.util;
  2 
  3 import java.lang.reflect.Field;
  4 import java.sql.Connection;
  5 import java.sql.DriverManager;
  6 import java.sql.PreparedStatement;
  7 import java.sql.ResultSet;
  8 import java.sql.SQLException;
  9 import java.util.ArrayList;
 10 import java.util.Arrays;
 11 import java.util.List;
 12 
 13 public class JDBCUtil {
 14     private final static String driver="com.mysql.jdbc.Driver";
 15     private final static String url="jdbc:mysql://192.168.137.11:3306/db_test?useUnicode=true&characterEncoding=utf8";
 16     private final static String user="root";
 17     private final static String password="123456";
 18     //获取JDBC连接
 19     public static Connection getConnection(){
 20         Connection conn=null;
 21         try {
 22             Class.forName(driver);
 23             conn=DriverManager.getConnection(url,user,password);
 24             
 25         } catch (ClassNotFoundException e) {
 26             // TODO 自动生成的 catch 块
 27             e.printStackTrace();
 28         } catch (SQLException e) {
 29             // TODO 自动生成的 catch 块
 30             e.printStackTrace();
 31         }
 32         return conn;
 33     }
 34     //关闭连接
 35     public static void close(Connection conn,PreparedStatement pstmt,ResultSet rs){
 36         if(rs!=null){
 37             try {
 38                 rs.close();
 39             } catch (SQLException e) {
 40                 // TODO 自动生成的 catch 块
 41                 e.printStackTrace();
 42             }
 43         }
 44         if(pstmt!=null){
 45             try {
 46                 pstmt.close();
 47             } catch (SQLException e) {
 48                 // TODO 自动生成的 catch 块
 49                 e.printStackTrace();
 50             }
 51         }
 52         if(conn!=null){
 53             try {
 54                 conn.close();
 55             } catch (SQLException e) {
 56                 // TODO 自动生成的 catch 块
 57                 e.printStackTrace();
 58             }
 59         }
 60     }
 61     //增、删、改
 62     /*
 63      * sql语句参数部分应改为?替代,代码中使用PreparedStatement类来注入参数,防止sql注入
 64      * 因不确定sql语句参数个数,类型,所以使用动态参数Object... objects 
 65      * 将objects使用PreparedStatement中setObject方法注入
 66      * 调用时可以这样调用
 67      * update("insert into user values(?,?)","ads","asdsa");
 68      * 这样封装使得此方法可重用性强
 69      */
 70     public static int update(String sql,Object... objects ){
 71         Connection conn=getConnection();
 72         PreparedStatement pstmt=null;
 73         int result =0;
 74         
 75         try {
 76             pstmt=conn.prepareStatement(sql);
 77             if(objects!=null){
 78                 for(int i=0;i<objects.length;i++){
 79                     pstmt.setObject(i+1, objects[i]);
 80                 }
 81             }
 82             result=pstmt.executeUpdate();
 83         } catch (SQLException e) {
 84             // TODO 自动生成的 catch 块
 85             e.printStackTrace();
 86         }finally {
 87             close(conn, pstmt, null);
 88         }
 89         
 90         
 91         return result;
 92     }
 93     
 94     //添加对象
 95     /*
 96      * 不确定未来编程时向数据库中添加对象是什么,固使用泛型T    
 97      * 可以使用自定义注解的方式实现javabean与相应数据表的映射
 98      * 此方法封装时代码晦涩难懂,使用时不用自己去写sql语句较为方便且复用性强
 99      * 类似于hibernate
100      */
101     public static <T> int insert(T t){
102         //列名数组,即javabean的属性,用于拼接sql语句
103         List<String> columns=new ArrayList<>();
104         //用于拼接sql语句,存放‘?’,若javabean有4个属性,则此数组为[?,?,?,?]
105         List<String> values=new ArrayList<>();
106         //存放javabean各个属性的值,最后使用PreparedStatement注入
107         List<Object> params=new ArrayList<>();
108         
109         Class clz=t.getClass();
110         //TableUtil自定义注解,用于javabean与表名的映射
111         TableUtil ann=(TableUtil)clz.getAnnotation(TableUtil.class);
112         //获取该javabean的属性
113         Field[] fields=clz.getDeclaredFields();
114         //for循环对columns values数组赋值
115         /*
116          * ColumnUtil自定义注解,用于javabean属性与表的列名映射
117          * IDUtil自定义注解,用于表的自增长主键与相应javabean属性映射
118          */
119         for (Field field : fields) {
120             //若数据表中设置了自增长主键,使用insert语句时须跳过相应的主属性,所以应执行此if语句判断
121             if(!field.isAnnotationPresent(IDUtil.class)){
122                 //判断是使用ColumnUtil将此属性映射
123                 if(field.isAnnotationPresent(ColumnUtil.class)){
124                     //获取列名
125                     ColumnUtil column= field.getAnnotation(ColumnUtil.class);
126                     //columns数组添加相应列名
127                     columns.add(column.value());
128                     //获取一列,便向values数组中添加一个‘?’,即有多少列就有多少个‘?’
129                     values.add("?");
130                     //一般javabean属性为private,使用此方法可访问private属性
131                     field.setAccessible(true);
132                     try {
133                         //列相应的值,存放入params数组
134                         params.add(field.get(t));
135                     } catch (IllegalArgumentException | IllegalAccessException e) {
136                         // TODO Auto-generated catch block
137                         e.printStackTrace();
138                     }
139                 }
140             }
141         }
142         /*
143          * 拼接sql语句
144          * ann.value()即注解的表名
145          * list数组转化为String,结果为[...],为拼接sql语句需将"[]"变"()"
146          */
147         String sql="insert into "+ann.value()+Arrays.toString(columns.toArray()).replaceAll("\\\\[", "(").replaceAll("\\\\]", ")")+" values"+Arrays.toString(values.toArray()).replaceAll("\\\\[", "(").replaceAll("\\\\]", ")");
148         //System.out.println(Arrays.toString(params.toArray()) );
149         //System.out.println(sql);
150         
151         //以下为执行sql语句过程
152         //思想同上面的update方法
153         Connection connection=getConnection();
154         PreparedStatement preparedStatement=null;
155         int result=0;
156         try {
157             preparedStatement=connection.prepareStatement(sql);
158             for (int i=0;i<params.size();i++) {
159                 preparedStatement.setObject(i+1,params.get(i));
160             }
161             result=preparedStatement.executeUpdate();
162             
163         } catch (SQLException e) {
164             // TODO 自动生成的 catch 块
165             e.printStackTrace();
166         }finally {
167             close(connection, preparedStatement, null);
168         }
169         
170         return result;
171         
172     }
173     
174     //查询,获取对象列表
175     /*
176      * 此方法调用时,使用匿名内部类,程序员可以自己写ResultSet结果集,具有好的复用性
177      * sql语句中参数部分使用?替代,并使用动态参数,思想同上
178      */
179     public static <T> List<T> executeQuery(String sql,RowMap<T> rowMap,Object...objects ){
180         List<T> list=new ArrayList<>();
181         Connection connection=getConnection();
182         PreparedStatement preparedStatement=null;
183         ResultSet rSet=null;
184         try {
185             preparedStatement=connection.prepareStatement(sql);
186             if(objects!=null) {
187                 for (int i=0;i<objects.length;i++) {
188                     preparedStatement.setObject(i+1, objects[i]);
189                     
190                 }
191             }
192             rSet=preparedStatement.executeQuery();
193             while (rSet.next()) {
194                 T t=rowMap.rowMapping(rSet);
195                 list.add(t);
196             }
197         } catch (SQLException e) {
198             // TODO 自动生成的 catch 块
199             e.printStackTrace();
200         }finally {
201             close(connection, preparedStatement, rSet);
202         }
203         
204         return list;
205     }
206     
207 }

以下为相关工具类

com.util.ColumnUtil.java

 1 package com.util;
 2 import java.lang.annotation.ElementType;
 3 import java.lang.annotation.Retention;
 4 import java.lang.annotation.RetentionPolicy;
 5 import java.lang.annotation.Target;
 6 @Target(ElementType.FIELD)
 7 @Retention(RetentionPolicy.RUNTIME)
 8 public @interface ColumnUtil {
 9     //相应列名
10     String value();
11 }

com.util.IDUtil.java

 1 package com.util;
 2 
 3 import java.lang.annotation.ElementType;
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.annotation.Target;
 7 
 8 
 9 @Target(ElementType.FIELD)
10 @Retention(RetentionPolicy.RUNTIME)
11 //自增主键注解
12 public @interface IDUtil {
13 
14 }

com.util.TableUtil.java

package com.util;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableUtil {
    //映射相应表名
    String value();
}

com.util.RowMap.java

package com.util;

import java.sql.ResultSet;

public interface RowMap<T> {
    //自定义result结果集
    //使用了匿名内部类的思想
    public T rowMapping(ResultSet rs);
}

以下为测试类:

com.model.User.java

package com.model;

import com.util.ColumnUtil;
import com.util.TableUtil;

@TableUtil("t_user")
//此javabean映射表名为"t_user"
public class User {
    @ColumnUtil("c_username")
    //属性username对应表中的c_username列
    private String username;
    //属性password对应表中的c_password列
    @ColumnUtil("c_password")
    private String password;
    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    

}

tests.JDBCUtilTest.java

 1 package tests;
 2 
 3 import java.sql.ResultSet;
 4 import java.sql.SQLException;
 5 import java.util.List;
 6 import java.util.UUID;
 7 
 8 import com.model.User;
 9 import com.util.JDBCUtil;
10 import com.util.RowMap;
11 
12 public class JDBCUtilTest {
13 
14     public static void main(String[] args) {
15         User newUser=new User();
16         newUser.setUsername(UUID.randomUUID().toString());
17         newUser.setPassword("asd");
18         JDBCUtil.insert(newUser);
19         List<User> users=JDBCUtil.executeQuery("select * from t_user where c_username!=?",new RowMap<User>() {
20             @Override
21             //匿名内部类 定义resultset结果集
22             public User rowMapping(ResultSet rs) {
23                 User user=new User();
24                 try {
25                     user.setUsername(rs.getString("c_username"));
26                     user.setPassword(rs.getString("c_password"));
27                 } catch (SQLException e) {
28                     e.printStackTrace();
29                 }
30                 return user;
31             }
32         }, "JDBCUtil");//查找用户名不为JDBCUtil的用户
33         for (User user : users) {
34             System.out.println(user.getUsername()+"&&"+user.getPassword());
35         }
36         
37     }
38 
39 }

测试结果:

相应数据库:

 

以上是关于优化JDBC封装的主要内容,如果未能解决你的问题,请参考以下文章

部分代码片段

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

采用DTO和DAO对JDBC程序进行进一步优化

Mybatis是啥以及Mybatis和JDBC的关系?