封装JDBC—非框架开发必备的封装类

一些小型的项目,有时不想使用框架如MyBatis,Hibernate等开发时,往往在数据持久化时操作比较繁琐,以下提供了对JDBC的封装类,简化JDBC操作。
为了更客观展示MyJDBC,我们通过一般的JDBC连接数据库的增删改查来对比。
JDBC连接数据库操作通常的做法都是先建立一个公共类,来配置数据库信息,加载驱动等,这里不展示公共类(网上到处都是)。
以下对比增删改查:

增(通常的代码):

[java]  view plain  copy
 print ?
  1. private static int insert(Student student) {  
  2.         Connection conn = getConn();  
  3.         int i = 0;  
  4.         String sql = "insert into students (Name,Sex,Age) values(?,?,?)";  
  5.         PreparedStatement pstmt;  
  6.         try {  
  7.             pstmt = (PreparedStatement) conn.prepareStatement(sql);  
  8.             pstmt.setString(1, student.getName());  
  9.             pstmt.setString(2, student.getSex());  
  10.             pstmt.setString(3, student.getAge());  
  11.             i = pstmt.executeUpdate();  
  12.             pstmt.close();  
  13.             conn.close();  
  14.         } catch (SQLException e) {  
  15.             e.printStackTrace();  
  16.         }  
  17.         return i;  
  18.     }  

使用MyJDBC:
[java]  view plain  copy
 print ?
  1. public void insert() throws Exception{  
  2.        String SQL = "insert into user_info(username,password) value (?,?)";  
  3.        MyJDBC.insert(SQL, true"阿木侠","12345");  
  4.    }  
对于单条数据的新增:
不需要使用类似pstmt.setString(1, student.getName());这样的语句一条一条对应占位符,MyJDBC提供了封装:MyJDBC.insert(SQL, autoGeneratedKeys, params)
SQL:需要执行的 INSERT 语句
autoGeneratedKeys:指示是否需要返回由数据库产生的键,当autoGeneratedKeys为true时,返回由数据库产生的主键的值,false时返回记录改变的条数。
params:使用了可变参数,无论多少位占位符,依次写入即可。

删:

[java]  view plain  copy
 print ?
  1. private static int delete(String name) {  
  2.     Connection conn = getConn();  
  3.     int i = 0;  
  4.     String sql = "delete from students where Name='" + name + "'";  
  5.     PreparedStatement pstmt;  
  6.     try {  
  7.         pstmt = (PreparedStatement) conn.prepareStatement(sql);  
  8.         i = pstmt.executeUpdate();  
  9.         System.out.println("resutl: " + i);  
  10.         pstmt.close();  
  11.         conn.close();  
  12.     } catch (SQLException e) {  
  13.         e.printStackTrace();  
  14.     }  
  15.     return i;  
  16. }  
使用MyJDBC:
  1. public void delete() throws Exception{  
  2.     String username = "阿木";  
  3.         String SQL = "delete from user_info where username like '%"+username+"%'";  
  4.         MyJDBC.execute(SQL);  
  5.     }  

改:

  1. private static int update(Student student) {  
  2.     Connection conn = getConn();  
  3.     int i = 0;  
  4.     String sql = "update students set Age='" + student.getAge() + "' where Name='" + student.getName() + "'";  
  5.     PreparedStatement pstmt;  
  6.     try {  
  7.         pstmt = (PreparedStatement) conn.prepareStatement(sql);  
  8.         i = pstmt.executeUpdate();  
  9.         System.out.println("resutl: " + i);  
  10.         pstmt.close();  
  11.         conn.close();  
  12.     } catch (SQLException e) {  
  13.         e.printStackTrace();  
  14.     }  
  15.     return i;  
  16. }  
使用MyJDBC:
  1. public void update() throws Exception{  
  2.         String SQL = "update user_info set password=? where id=2";  
  3.         MyJDBC.execute(SQL, "123321");  
  4.     }  

查:

  1. private static Integer getAll() {  
  2.     Connection conn = getConn();  
  3.     String SQL = "select id,password from user_info where username= ?";  
  4.     PreparedStatement pstmt;  
  5.     try {  
  6.         pstmt = (PreparedStatement)conn.prepareStatement(SQL);  
  7.         ResultSet rs = pstmt.executeQuery();  
  8.         while (rs.next()) {  
  9.             User user = new User();  
  10.             user.setId(rs.getInt(1));  
  11.             user.setUsername(rs.getString(2));  
  12.             user.setPassword(rs.getString(3));  
  13.             System.out.println("用户信息"+user);  
  14.             System.out.println("");  
  15.         }  
  16.     } catch (SQLException e) {  
  17.         e.printStackTrace();  
  18.     }  
  19.     return null;  
  20. }  
使用MyJDBC:
  1. public void query() throws Exception{  
  2.     String name = "阿木侠";  
  3.     String SQL = "select id,password from user_info where username= ?";  
  4.     ResultSet rs = MyJDBC.query(SQL,name);  
  5.         if(rs.next()){  
  6.             User user = new User();  
  7.             user.setId(rs.getInt(1));  
  8.             user.setUsername(name);  
  9.             user.setPassword(rs.getString(2));  
  10.             System.out.println("用户信息"+user);  
  11.       }  
  12.     }  

我们可以看到,代码确实简化了好多,Statement,Connection,ResultSet都不需要去手动操作,关闭,全部由MyJDBC代理。
不仅如此,还提供了execute()方法对SQL进行基本的操作。
下面贴出MyJDBC封装类:
  1. import java.sql.Connection;  
  2. import java.sql.DriverManager;  
  3. import java.sql.PreparedStatement;  
  4. import java.sql.ResultSet;  
  5. import java.sql.SQLException;  
  6. import java.sql.Statement;  
  7.   
  8. /** 
  9.  * @author 
  10.  */  
  11. public final class MyJDBC {  
  12.   
  13.     private static String connect;  
  14.     private static String driverClassName;  
  15.     private static String URL;  
  16.     private static String username;  
  17.     private static String password;  
  18.     private static boolean autoCommit;  
  19.   
  20.     /** 声明一个 Connection类型的静态属性,用来缓存一个已经存在的连接对象 */  
  21.     private static Connection conn;  
  22.   
  23.     static {  
  24.     config();  
  25.     }  
  26.   
  27.     /** 
  28.      * 开头配置自己的数据库信息 
  29.      */  
  30.     private static void config() {  
  31.     /* 
  32.      * 获取驱动 
  33.      */  
  34.     driverClassName = "com.mysql.jdbc.Driver";  
  35.     /* 
  36.      * 获取URL 
  37.      */  
  38.     URL = "jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf8";  
  39.     /* 
  40.      * 获取用户名 
  41.      */  
  42.     username = "root";  
  43.     /* 
  44.      * 获取密码 
  45.      */  
  46.     password = "1234";  
  47.     /* 
  48.      * 设置是否自动提交,一般为false不用改 
  49.      */  
  50.     autoCommit = false;  
  51.   
  52.     }  
  53.   
  54.     /** 
  55.      * 载入数据库驱动类 
  56.      */  
  57.     private static boolean load() {  
  58.     try {  
  59.         Class.forName(driverClassName);  
  60.         return true;  
  61.     } catch (ClassNotFoundException e) {  
  62.         System.out.println("驱动类 " + driverClassName + " 加载失败");  
  63.     }  
  64.   
  65.     return false;  
  66.     }  
  67.   
  68.     /** 
  69.      * 专门检查缓存的连接是否不可以被使用 ,不可以被使用的话,就返回 true 
  70.      */  
  71.     private static boolean invalid() {  
  72.     if (conn != null) {  
  73.         try {  
  74.         if (conn.isClosed() || !conn.isValid(3)) {  
  75.             return true;  
  76.             /* 
  77.              * isValid方法是判断Connection是否有效,如果连接尚未关闭并且仍然有效,则返回 true 
  78.              */  
  79.         }  
  80.         } catch (SQLException e) {  
  81.         e.printStackTrace();  
  82.         }  
  83.         /* 
  84.          * conn 既不是 null 且也没有关闭 ,且 isValid 返回 true,说明是可以使用的 ( 返回 false ) 
  85.          */  
  86.         return false;  
  87.     } else {  
  88.         return true;  
  89.     }  
  90.     }  
  91.   
  92.     /** 
  93.      * 建立数据库连接 
  94.      */  
  95.     public static Connection connect() {  
  96.     if (invalid()) { /* invalid为true时,说明连接是失败的 */  
  97.         /* 加载驱动 */  
  98.         load();  
  99.         try {  
  100.         /* 建立连接 */  
  101.         conn = DriverManager.getConnection(URL, username, password);  
  102.         } catch (SQLException e) {  
  103.         System.out.println("建立 " + connect + " 数据库连接失败 , " + e.getMessage());  
  104.         }  
  105.     }  
  106.     return conn;  
  107.     }  
  108.   
  109.     /** 
  110.      * 设置是否自动提交事务 
  111.      **/  
  112.     public static void transaction() {  
  113.   
  114.     try {  
  115.         conn.setAutoCommit(autoCommit);  
  116.     } catch (SQLException e) {  
  117.         System.out.println("设置事务的提交方式为 : " + (autoCommit ? "自动提交" : "手动提交") + " 时失败: " + e.getMessage());  
  118.     }  
  119.   
  120.     }  
  121.   
  122.     /** 
  123.      * 创建 Statement 对象 
  124.      */  
  125.     public static Statement statement() {  
  126.     Statement st = null;  
  127.     connect();  
  128.     /* 如果连接是无效的就重新连接 */  
  129.     transaction();  
  130.     /* 设置事务的提交方式 */  
  131.     try {  
  132.         st = conn.createStatement();  
  133.     } catch (SQLException e) {  
  134.         System.out.println("创建 Statement 对象失败: " + e.getMessage());  
  135.     }  
  136.   
  137.     return st;  
  138.     }  
  139.   
  140.     /** 
  141.      * 根据给定的带参数占位符的SQL语句,创建 PreparedStatement 对象 
  142.      *  
  143.      * @param SQL 
  144.      *            带参数占位符的SQL语句 
  145.      * @return 返回相应的 PreparedStatement 对象 
  146.      */  
  147.     private static PreparedStatement prepare(String SQL, boolean autoGeneratedKeys) {  
  148.   
  149.     PreparedStatement ps = null;  
  150.     connect();  
  151.     /* 如果连接是无效的就重新连接 */  
  152.     transaction();  
  153.     /* 设置事务的提交方式 */  
  154.     try {  
  155.         if (autoGeneratedKeys) {  
  156.         ps = conn.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);  
  157.         } else {  
  158.         ps = conn.prepareStatement(SQL);  
  159.         }  
  160.     } catch (SQLException e) {  
  161.         System.out.println("创建 PreparedStatement 对象失败: " + e.getMessage());  
  162.     }  
  163.   
  164.     return ps;  
  165.   
  166.     }  
  167.   
  168.   
  169.     public static ResultSet query(String SQL, Object... params) {  
  170.   
  171.     if (SQL == null || SQL.trim().isEmpty() || !SQL.trim().toLowerCase().startsWith("select")) {  
  172.         throw new RuntimeException("你的SQL语句为空或不是查询语句");  
  173.     }  
  174.     ResultSet rs = null;  
  175.     if (params.length > 0) {  
  176.         /* 说明 有参数 传入,就需要处理参数 */  
  177.         PreparedStatement ps = prepare(SQL, false);  
  178.         try {  
  179.         for (int i = 0; i < params.length; i++) {  
  180.             ps.setObject(i + 1, params[i]);  
  181.         }  
  182.         rs = ps.executeQuery();  
  183.         } catch (SQLException e) {  
  184.         System.out.println("执行SQL失败: " + e.getMessage());  
  185.         }  
  186.     } else {  
  187.         /* 说明没有传入任何参数 */  
  188.         Statement st = statement();  
  189.         try {  
  190.         rs = st.executeQuery(SQL); // 直接执行不带参数的 SQL 语句  
  191.         } catch (SQLException e) {  
  192.         System.out.println("执行SQL失败: " + e.getMessage());  
  193.         }  
  194.     }  
  195.   
  196.     return rs;  
  197.   
  198.     }  
  199.   
  200.   
  201.     private static Object typeof(Object o) {  
  202.     Object r = o;  
  203.   
  204.     if (o instanceof java.sql.Timestamp) {  
  205.         return r;  
  206.     }  
  207.     // 将 java.util.Date 转成 java.sql.Date  
  208.     if (o instanceof java.util.Date) {  
  209.         java.util.Date d = (java.util.Date) o;  
  210.         r = new java.sql.Date(d.getTime());  
  211.         return r;  
  212.     }  
  213.     // 将 Character 或 char 变成 String  
  214.     if (o instanceof Character || o.getClass() == char.class) {  
  215.         r = String.valueOf(o);  
  216.         return r;  
  217.     }  
  218.     return r;  
  219.     }  
  220.   
  221.   
  222.     public static boolean execute(String SQL, Object... params) {  
  223.     if (SQL == null || SQL.trim().isEmpty() || SQL.trim().toLowerCase().startsWith("select")) {  
  224.         throw new RuntimeException("你的SQL语句为空或有错");  
  225.     }  
  226.     boolean r = false;  
  227.     /* 表示 执行 DDL 或 DML 操作是否成功的一个标识变量 */  
  228.   
  229.     /* 获得 被执行的 SQL 语句的 前缀 */  
  230.     SQL = SQL.trim();  
  231.     SQL = SQL.toLowerCase();  
  232.     String prefix = SQL.substring(0, SQL.indexOf(" "));  
  233.     String operation = ""// 用来保存操作类型的 变量  
  234.     // 根据前缀 确定操作  
  235.     switch (prefix) {  
  236.     case "create":  
  237.         operation = "create table";  
  238.         break;  
  239.     case "alter":  
  240.         operation = "update table";  
  241.         break;  
  242.     case "drop":  
  243.         operation = "drop table";  
  244.         break;  
  245.     case "truncate":  
  246.         operation = "truncate table";  
  247.         break;  
  248.     case "insert":  
  249.         operation = "insert :";  
  250.         break;  
  251.     case "update":  
  252.         operation = "update :";  
  253.         break;  
  254.     case "delete":  
  255.         operation = "delete :";  
  256.         break;  
  257.     }  
  258.     if (params.length > 0) { // 说明有参数  
  259.         PreparedStatement ps = prepare(SQL, false);  
  260.         Connection c = null;  
  261.         try {  
  262.         c = ps.getConnection();  
  263.         } catch (SQLException e) {  
  264.         e.printStackTrace();  
  265.         }  
  266.         try {  
  267.         for (int i = 0; i < params.length; i++) {  
  268.             Object p = params[i];  
  269.             p = typeof(p);  
  270.             ps.setObject(i + 1, p);  
  271.         }  
  272.         ps.executeUpdate();  
  273.         commit(c);  
  274.         r = true;  
  275.         } catch (SQLException e) {  
  276.         System.out.println(operation + " 失败: " + e.getMessage());  
  277.         rollback(c);  
  278.         }  
  279.   
  280.     } else { // 说明没有参数  
  281.   
  282.         Statement st = statement();  
  283.         Connection c = null;  
  284.         try {  
  285.         c = st.getConnection();  
  286.         } catch (SQLException e) {  
  287.         e.printStackTrace();  
  288.         }  
  289.         // 执行 DDL 或 DML 语句,并返回执行结果  
  290.         try {  
  291.         st.executeUpdate(SQL);  
  292.         commit(c); // 提交事务  
  293.         r = true;  
  294.         } catch (SQLException e) {  
  295.         System.out.println(operation + " 失败: " + e.getMessage());  
  296.         rollback(c); // 回滚事务  
  297.         }  
  298.     }  
  299.     return r;  
  300.     }  
  301.   
  302.     /* 
  303.      *  
  304.      * @param SQL 
  305.      *            需要执行的 INSERT 语句 
  306.      * @param autoGeneratedKeys 
  307.      *            指示是否需要返回由数据库产生的键 
  308.      * @param params 
  309.      *            将要执行的SQL语句中包含的参数占位符的 参数值 
  310.      * @return 如果指定 autoGeneratedKeys 为 true 则返回由数据库产生的键; 如果指定 autoGeneratedKeys 
  311.      *         为 false 则返回受当前SQL影响的记录数目 
  312.      */  
  313.     public static int insert(String SQL, boolean autoGeneratedKeys, Object... params) {  
  314.     int var = -1;  
  315.     if (SQL == null || SQL.trim().isEmpty()) {  
  316.         throw new RuntimeException("你没有指定SQL语句,请检查是否指定了需要执行的SQL语句");  
  317.     }  
  318.     // 如果不是 insert 开头开头的语句  
  319.     if (!SQL.trim().toLowerCase().startsWith("insert")) {  
  320.         System.out.println(SQL.toLowerCase());  
  321.         throw new RuntimeException("你指定的SQL语句不是插入语句,请检查你的SQL语句");  
  322.     }  
  323.     // 获得 被执行的 SQL 语句的 前缀 ( 第一个单词 )  
  324.     SQL = SQL.trim();  
  325.     SQL = SQL.toLowerCase();  
  326.     if (params.length > 0) { // 说明有参数  
  327.         PreparedStatement ps = prepare(SQL, autoGeneratedKeys);  
  328.         Connection c = null;  
  329.         try {  
  330.         c = ps.getConnection(); // 从 PreparedStatement 对象中获得 它对应的连接对象  
  331.         } catch (SQLException e) {  
  332.         e.printStackTrace();  
  333.         }  
  334.         try {  
  335.         for (int i = 0; i < params.length; i++) {  
  336.             Object p = params[i];  
  337.             p = typeof(p);  
  338.             ps.setObject(i + 1, p);  
  339.         }  
  340.         int count = ps.executeUpdate();  
  341.         if (autoGeneratedKeys) { // 如果希望获得数据库产生的键  
  342.             ResultSet rs = ps.getGeneratedKeys(); // 获得数据库产生的键集  
  343.             if (rs.next()) { // 因为是保存的是单条记录,因此至多返回一个键  
  344.             var = rs.getInt(1); // 获得值并赋值给 var 变量  
  345.             }  
  346.         } else {  
  347.             var = count; // 如果不需要获得,则将受SQL影像的记录数赋值给 var 变量  
  348.         }  
  349.         commit(c);  
  350.         } catch (SQLException e) {  
  351.         System.out.println("数据保存失败: " + e.getMessage());  
  352.         rollback(c);  
  353.         }  
  354.     } else { // 说明没有参数  
  355.         Statement st = statement();  
  356.         Connection c = null;  
  357.         try {  
  358.         c = st.getConnection(); // 从 Statement 对象中获得 它对应的连接对象  
  359.         } catch (SQLException e) {  
  360.         e.printStackTrace();  
  361.         }  
  362.         // 执行 DDL 或 DML 语句,并返回执行结果  
  363.         try {  
  364.         int count = st.executeUpdate(SQL);  
  365.         if (autoGeneratedKeys) { // 如果企望获得数据库产生的键  
  366.             ResultSet rs = st.getGeneratedKeys(); // 获得数据库产生的键集  
  367.             if (rs.next()) { // 因为是保存的是单条记录,因此至多返回一个键  
  368.             var = rs.getInt(1); // 获得值并赋值给 var 变量  
  369.             }  
  370.         } else {  
  371.             var = count; // 如果不需要获得,则将受SQL影像的记录数赋值给 var 变量  
  372.         }  
  373.         commit(c); // 提交事务  
  374.         } catch (SQLException e) {  
  375.         System.out.println("数据保存失败: " + e.getMessage());  
  376.         rollback(c); // 回滚事务  
  377.         }  
  378.     }  
  379.     return var;  
  380.     }  
  381.   
  382.     /** 提交事务 */  
  383.     private static void commit(Connection c) {  
  384.     if (c != null && !autoCommit) {  
  385.         try {  
  386.         c.commit();  
  387.         } catch (SQLException e) {  
  388.         e.printStackTrace();  
  389.         }  
  390.     }  
  391.     }  
  392.   
  393.     /** 回滚事务 */  
  394.     private static void rollback(Connection c) {  
  395.     if (c != null && !autoCommit) {  
  396.         try {  
  397.         c.rollback();  
  398.         } catch (SQLException e) {  
  399.         e.printStackTrace();  
  400.         }  
  401.     }  
  402.     }  
  403.   
  404.   
  405.     /** 
  406.      *  释放资源 
  407.      *   **/  
  408.     public static void release(Object cloaseable) {  
  409.   
  410.     if (cloaseable != null) {  
  411.   
  412.         if (cloaseable instanceof ResultSet) {  
  413.         ResultSet rs = (ResultSet) cloaseable;  
  414.         try {  
  415.             rs.close();  
  416.         } catch (SQLException e) {  
  417.             e.printStackTrace();  
  418.         }  
  419.         }  
  420.   
  421.         if (cloaseable instanceof Statement) {  
  422.         Statement st = (Statement) cloaseable;  
  423.         try {  
  424.             st.close();  
  425.         } catch (SQLException e) {  
  426.             e.printStackTrace();  
  427.         }  
  428.         }  
  429.   
  430.         if (cloaseable instanceof Connection) {  
  431.         Connection c = (Connection) cloaseable;  
  432.         try {  
  433.             c.close();  
  434.         } catch (SQLException e) {  
  435.             e.printStackTrace();  
  436.         }  
  437.         }  
  438.   
  439.     }  
  440.   
  441.     }  
  442.   
  443. }  

以上,没有最方便的代码,只会有更方便的,欢迎大家指正,有什么好的建议欢迎留言,随时作出调整。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值