简易 DBUtil 封装

                                                    

Dao包结构图:

                                             

1.首先连接数据库

 1 package com.util.db;
 2 
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 import java.sql.Statement;
 8 import java.util.ResourceBundle;
 9 
10 import javax.management.loading.PrivateClassLoader;
11 
12 import org.omg.CORBA.PRIVATE_MEMBER;
13 
14 /**
15  * 连接数据库
16  * @author Administrator
17  *
18  */
19 public class DBConn {
20 public static String URL;
21 public static String USERNAME;
22 public static String PASSWORD;
23 public static String DRIVER;
24 private static  ResourceBundle resourceBundle = ResourceBundle.getBundle("com.util.db.db_config");
25 private DBConn() {}
26 /**
27  *为连接数据库变量赋值 
28  *加载jdbc驱动
29  */
30 static{
31     URL = resourceBundle.getString("jdbc.url");
32     USERNAME = resourceBundle.getString("jdbc.username");
33     PASSWORD = resourceBundle.getString("jdbc.password");
34     DRIVER = resourceBundle.getString("jdbc.driver");
35     try {
36         Class.forName(DRIVER);
37     } catch (ClassNotFoundException e) {
38         e.printStackTrace();
39     }
40 }
41 /**
42  * 连接数据库,若连接失败则返回空
43  * @return
44  */
45 public static Connection getConnection() {
46     Connection conn = null;
47     try {
48         conn = DriverManager.getConnection(URL, USERNAME,PASSWORD);
49         System.out.println("连接成功!");
50     } catch (SQLException e) {
51         e.printStackTrace();
52         System.out.println("连接失败");
53     }
54     return conn;
55 }
56 /**
57  * 关闭数据库连接
58  * @param rs
59  * @param st
60  * @param conn
61  */
62 public static void close(ResultSet rs,Statement st,Connection conn){
63     try {
64         if (rs != null) {rs.close();}
65         if (st != null) {st.close();}
66         if (conn !=null) {conn.close();}
67     } catch (SQLException e) {
68         e.printStackTrace();
69     }
70     
71 }
72 public static void main(String[] args) {
73     System.out.println(URL);
74     System.out.println(USERNAME);
75     System.out.println(PASSWORD);
76     System.out.println(DRIVER);
77     
78 }
79 }

连接所需配置文件如下:

jdbc.url = jdbc:mysql://localhost:3306/test?characterEncoding=utf8
jdbc.username = root
jdbc.password = 000000
jdbc.driver =com.mysql.jdbc.Driver

2.对增删该查基本操作做定义  使用不定参数 来解决增删改的参数不同

 1 package com.util.db;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 
 8 /**
 9  * 为数据库操作提供方法模板
10  * @author Administrator
11  *
12  */
13 public class JdbcTemplete {
14     /**
15      * 更新操作
16      * 返回 int 类型的操作行数 用作判断操作成功与否
17      * 若操作异常  则返回 -1
18      * @param sql
19      * @param args
20      * @return
21      */
22 public int update(String sql,Object...args){
23     Connection conn = null;
24     PreparedStatement ps =  null;
25     conn = DBConn.getConnection();
26     try {
27         ps = conn.prepareStatement(sql);
28         if(args!=null){
29             for(int i = 0; i< args.length; i++){
30             ps.setObject(i+1, args[i]);    
31             }
32         }
33       
34         int rs =  ps.executeUpdate();
35         System.out.println("操作成功!");
36         return rs;
37     } catch (SQLException e) {
38         e.printStackTrace();
39 //        try {
40 //            //事务回滚
41 //            conn.rollback();
42 //        } catch (SQLException e1) {e1.printStackTrace();}
43         System.out.println("更新异常");
44         return -1;
45     }finally{
46         DBConn.close(null, ps, conn);
47     }    
48 }
49 /**
50  *  查询操作 不做结果处理
51  *  结果处理放在  ResultSetHandler 
52  *  由调用时编写匿名类  采用策略模式  使用户采用不同策略 处理不同对象
53  * @param sql
54  * @param handler
55  * @param args
56  * @return
57  */
58 public Object query(String sql, ResultSetHandler handler, Object...args) {
59     Connection conn = null;
60     PreparedStatement ps = null;
61     ResultSet rs = null;
62     try {
63         conn = DBConn.getConnection();
64         ps = conn.prepareStatement(sql);
65         if (args != null) {
66             for (int i = 0; i < args.length; i++) {
67                 ps.setObject(i+1, args[i]);
68             }
69         }
70         rs = ps.executeQuery();
71         return handler.doHandler(rs);
72     } catch (SQLException e) {
73         e.printStackTrace();
74         return null;
75     }finally{
76         DBConn.close(rs, ps, conn);
77     }
78 }
79 }

3.对操作查询结果作出接口声明  使用策略模式  对于不同的javaBean有不同的处理

package com.util.db;

import java.sql.ResultSet;
import java.sql.SQLException;
/**
 * 操作连接数据库的结果集
 * 声明接口可以对具体的实体做不同处理
 * @author Administrator
 *
 */
public interface ResultSetHandler {
public Object doHandler(ResultSet rs) throws SQLException;
}

4.定义javaBean

 1 package com.domain;
 2 
 3 public class Person {
 4 private int id;
 5 private String name;
 6 private int age;
 7 private String description;
 8 public Person() {
 9     super();
10 }
11 public Person(String name, int age, String description) {
12     super();
13     this.name = name;
14     this.age = age;
15     this.description = description;
16 }
17 public Person(int id, String name, int age, String description) {
18     super();
19     this.id = id;
20     this.name = name;
21     this.age = age;
22     this.description = description;
23 }
24 public int getId() {
25     return id;
26 }
27 public void setId(int id) {
28     this.id = id;
29 }
30 public String getName() {
31     return name;
32 }
33 public void setName(String name) {
34     this.name = name;
35 }
36 public int getAge() {
37     return age;
38 }
39 public void setAge(int age) {
40     this.age = age;
41 }
42 public String getDescription() {
43     return description;
44 }
45 public void setDescription(String description) {
46     this.description = description;
47 }
48 @Override
49 public String toString() {
50     return "Person [id=" + id + ", name=" + name + ", age=" + age
51             + ", description=" + description + "]";
52 }
53 
54 }

5. 定义Dao  对具体操作  声明接口

 1 package com.dao;
 2 
 3 import java.sql.SQLException;
 4 import java.util.List;
 5 
 6 import com.domain.Person;
 7 
 8 /**
 9  * 用户功能接口
10  * @author Administrator
11  *
12  */
13 public interface PersonDao {
14 public void add(Person person)throws SQLException;
15 public void update(Person person)throws SQLException;
16 public void delete (int id)throws SQLException;
17 public Person findById(int id)throws SQLException;
18 public List findAll()throws SQLException;
19 
20 
21 } 

6.对用户的操作进行实现

 1 package com.dao.impl;
 2 
 3 import java.sql.ResultSet;
 4 import java.sql.SQLException;
 5 import java.util.ArrayList;
 6 import java.util.List;
 7 
 8 import javax.management.j2ee.statistics.JDBCConnectionPoolStats;
 9 
10 import com.dao.PersonDao;
11 import com.domain.Person;
12 import com.util.db.JdbcTemplete;
13 import com.util.db.ResultSetHandler;
14 
15 public class PersonDaoImpl implements PersonDao {
16 private JdbcTemplete jdbcTemplete;
17 public PersonDaoImpl(){
18     jdbcTemplete = new JdbcTemplete();
19 }
20     /**
21      * 添加
22      */
23     @Override
24     public void add(Person person) throws SQLException {
25        String sql = "insert into person(name,age,description)value(?,?,?)";
26        jdbcTemplete.update(sql, person.getName(),person.getAge(),person.getDescription());
27     
28     }
29     /**
30      * 更新操作
31      */
32     @Override
33     public void update(Person person) throws SQLException {
34            String sql ="update person set name=?,age=?,description=? where id=?";
35            jdbcTemplete.update(sql, person.getName(),person.getAge(),person.getDescription(),person.getId());
36     }
37 
38     @Override
39     public void delete(int id) throws SQLException {
40         String sql = "delete from person where id = ?";
41         jdbcTemplete.update(sql,id);
42     }
43 
44     @Override
45     public Person findById(final int id) throws SQLException {
46         String sql = "select name,age,description from person where id =?";
47           return (Person) jdbcTemplete.query(sql, new ResultSetHandler() {
48             @Override
49             public Object doHandler(ResultSet rs) throws SQLException {
50                 Person person = null;
51                 if (rs.next()) {
52                     person = new Person();
53                     person.setId(rs.getInt(id));
54                     person.setName(rs.getString(1));
55                     person.setAge(rs.getInt(2));
56                     person.setDescription(rs.getString(3));
57                 }
58                 return person;
59             }
60         },id );
61     
62     }
63 
64     @Override
65     public List findAll() throws SQLException {
66         String sql = "select id,name,age,description from person";
67         return (List) jdbcTemplete.query(sql,new ResultSetHandler() {
68             @Override
69             public Object doHandler(ResultSet rs) throws SQLException {
70                 List<Person> personList = new ArrayList<>();
71                 Person person =null;
72                 while (rs.next()) {
73                     person = new Person();
74                     person.setId(rs.getInt(1));
75                     person.setName(rs.getString(2));
76                     person.setAge(rs.getInt(3));
77                     person.setDescription(rs.getString(4));
78                     personList.add(person);
79                 }
80                 return personList;
81             }
82         });
83         
84     }
85 
86 }

7.编写测试类

 1 package com.test;
 2 
 3 import java.sql.SQLException;
 4 import java.util.List;
 5 
 6 import com.dao.PersonDao;
 7 import com.dao.impl.PersonDaoImpl;
 8 import com.domain.Person;
 9 
10 public class Test {
11     /**
12      * 
13      * @param args
14      */
15 public static void main(String[] args) {
16     PersonDao personDao = new PersonDaoImpl();
17 
18     try {
19 
20 //        personDao.add(new Person("CCC", 13, "CCC"));
21         
22         personDao.delete(3);
23 //        
24 //        personDao.update(new Person(3, "DDD", 10, "DDD"));
25 //        
26 //        
27 //        Person p4 = personDao.findById(2);
28 //        System.out.println(p4.toString());
29 //        
30 //        
31 //        List<Person> personList = personDao.findAll();
32 //        for (Person p : personList) {
33 //            System.out.println(p.toString());
34 //        }
35         
36     } catch (SQLException e) {
37         e.printStackTrace();
38     }
39 }
40 }
1.Statement、PreparedStatement和CallableStatement都是接口(interface)。  
2.Statement继承自Wrapper、PreparedStatement继承自Statement、CallableStatement继承自PreparedStatement。 
3.  
 a.Statement:  
    普通的不带参的查询SQL;支持批量更新,批量删除;  
 b.PreparedStatement:  
    可变参数的SQL,支持占位符,每个占位符可占一个位,
     编译一次,执行多次,效率高;  
    安全性好,有效防止Sql注入等问题;  
    支持批量更新,批量删除;  
 c.CallableStatement:  
    继承自PreparedStatement,支持带参数的SQL操作;  
    支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持; 

PreparedStatement是预编译的,使用PreparedStatement有几个好处  
1. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。 
2. 安全性好,有效防止Sql注入等问题。  
3.  对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch;  
4.  代码的可读性和可维护性。

如何防止注入攻击:

 如果你是做Java web应用开发的,那么必须熟悉那声名狼藉的SQL注入式攻击。去年Sony就遭受了SQL注入攻击,被盗用了一些Sony play station(PS机)用户的数据。在SQL注入攻击里,恶意用户通过SQL元数据绑定输入,比如:某个网站的登录验证SQL查询代码为:

strSQL = "SELECT * FROM users WHERE name = '" + userName + "' and pw = '"+ passWord +"';"

 恶意填入:

userName = "1' OR '1'='1";
passWord = "1' OR '1'='1"

那么最终SQL语句变成了:

strSQL = "SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"

 因为WHERE条件恒为真,这就相当于执行:

strSQL = "SELECT * FROM users;"

 因此可以达到无账号密码亦可登录网站。如果恶意用户要是更坏一点,再在后面加一句  :

drop  table users;

SQL语句变成了:

strSQL = "SELECT * FROM users;drop  table users;

 这样一来,虽然没有登录,但是数据表都被删除了。

   然而使用PreparedStatement的参数化的查询可以阻止大部分的SQL注入。在使用参数化查询的情况下,数据库系统(eg:MySQL)不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,参数只是用作参数,而不会作为指令拼成SQL语句,因此就算参数中含有破坏性的指令,也不会被数据库所运行。
补充:避免SQL注入的第二种方式:
在组合SQL字符串的时候,先对所传入的参数做字符取代(将单引号字符取代为连续2个单引号字符,因为连续2个单引号字符在SQL数据库中会视为字符中的一个单引号字符,譬如:

strSQL = "SELECT * FROM users WHERE name = '" + userName + "';"

 传入字符串:

userName  = " 1' OR 1=1 "

把userName做字符替换后变成:

userName = " 1'' OR 1=1"

最后生成的SQL查询语句为:

strSQL = "SELECT * FROM users WHERE name = '1'' OR 1=1'

这样数据库就会去系统查找name为“     1′ OR 1=1     ”的记录,而避免了SQL注入。

CallableStatement使用:

  

public class Conn {
    public static String URL;
    public static String USERNAME;
    public static String PASSWORD;
    public static String DRIVER;
    private static  ResourceBundle resourceBundle = ResourceBundle.getBundle("com.util.db.db_config");
    private void Conn() {}
    static{
        URL = resourceBundle.getString("jdbc.url");
        USERNAME = resourceBundle.getString("jdbc.username");
        PASSWORD = resourceBundle.getString("jdbc.password");
        DRIVER = resourceBundle.getString("jdbc.driver");
        try {
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    /**
     * 连接数据库,若连接失败则返回空
     * @return
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(URL, USERNAME,PASSWORD);
            System.out.println("连接成功!");
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("连接失败");
        }
        return conn;
    }
    /**
     * 关闭数据库连接
     * @param rs
     * @param st
     * @param conn
     */
    public static void close(ResultSet rs,CallableStatement cstmt,Connection conn){
        try {
            if (rs != null) {rs.close();}
            if (cstmt != null) {cstmt.close();}
            if (conn !=null) {conn.close();}
        } catch (SQLException e) {
            e.printStackTrace();
        }  
    }
    
/**
 * 1、执行不带参数但有返回值的存储过程    
 */    
static public  int getUserCount() {
    Connection conn = Conn.getConnection();
    CallableStatement  cstmt = null;
    int rowsCount = 0; 
    try {
        String sql = "{call getUserCount(?)}";
        //创建CallableStatement 对象
        cstmt = conn.prepareCall(sql);
        //注册输出参数
        cstmt.registerOutParameter(1,Types.INTEGER);
        //执行存储过程
        cstmt.execute();
        
        rowsCount = cstmt.getInt(1);
    } catch (SQLException e) {
        System.out.println("执行失败!");
        e.printStackTrace();
    }finally {
        Conn.close(null,cstmt, conn);
        return rowsCount;
    }
}
/**
 *     2、执行带参数带返回值的存储过程
 */
static public int getUserCountCondit(String username) {
    Connection conn = Conn.getConnection();
    CallableStatement  cstmt = null;
    int rowsCount = 0; 
    try {
        String sql = "{call proc_getUserCountCondit(?,?)}";
        //创建CallableStatement 对象
        cstmt = conn.prepareCall(sql);
        //输入参数赋值
        cstmt.setString(1,username);
        //注册输出参数
        cstmt.registerOutParameter(1,Types.INTEGER);
        //执行存储过程
        cstmt.execute();
        
        rowsCount = cstmt.getInt(1);
    } catch (SQLException e) {
        System.out.println("执行失败!");
        e.printStackTrace();
    }finally {
        Conn.close(null,cstmt, conn);
        return rowsCount;
    }
}    
/**
 * 3、执行返回值为游标的存储过程
 */
static public List<User> getUserListByProc(){
    Connection conn = Conn.getConnection();
    CallableStatement  cstmt = null;
    ResultSet rs = null;
    List<User> userList = new ArrayList();
    try {
        String sql = "{? = call FUNC_GETUSERNAME(?)}";
        //创建CallableStatement 对象
        cstmt = conn.prepareCall(sql);
        //注册输出参数
        cstmt.registerOutParameter(1,Types.REF_CURSOR);
        //执行存储过程
        cstmt.execute();
        rs = cstmt.getResultSet();

        while (rs.next()) {
            String username = rs.getString("username");
            String password = rs.getString("password");
            userList.add(new User(username, password));        
        }
    } catch (SQLException e) {
        System.out.println("执行失败!");
        e.printStackTrace();
    }finally {
        Conn.close(rs,cstmt, conn);
        return userList;
    }
}
public static void main(String[] args) {
    
    

    
}


static class User{
    String username = null;
    String password = null;
    
    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
}
}
原文地址:https://www.cnblogs.com/the-wang/p/7535195.html