javaweb三、JDBC访问数据库

JDBC是J2SE的内容,是由java提供的访问数据库的接口,但没有提供具体的实现方法,需要数据库厂商提供,就是对应的数据库驱动。

这样的好处是可以方便的更换数据库,提高了扩展性。这也是面向接口编程的一个优点。

  1 import java.sql.Connection;
  2 import java.sql.DriverManager;
  3 import java.sql.ResultSet;
  4 import java.sql.SQLException;
  5 import java.sql.Statement;
  6 
  7 public class Demo {
  8     public static void main(String[] args) throws ClassNotFoundException, SQLException{
  9         //连接数据库,获取连接对象
 10         Connection conn=connection();
 11         //使用连接对象进行数据库的操作:增、删、改
 12         sqlDemo(conn);
 13         //使用连接对象进行数据库的操作:查
 14         queryDemo(conn);
 15                 //sql规范写法,
 16                 sqlDemo2();
 17     }
 18 
 19     public static Connection connection() throws ClassNotFoundException, SQLException {
 20         
 21         /*注册数据库驱动对象的简便方法:
 22          * Java中在使用数据库对象时,需要通过相应的驱动来实现,并且要通过DriverManager类来注册这个驱动
 23          * 上面的操作已经被写入驱动类中的静态代码块中了,所以可以直接加载该类就实现了上述操作
 24          * 
 25          * 在jdbc4.0之后的版本中有些数据库驱动有一个配置文件可以进行注册,也就是可以省略下面一句,
 26          * 但是并非所有驱动都可以,而且为了兼容性更好,建议使用
 27          */
 28         Class.forName("com.mysql.jdbc.Driver");
 29         
 30         //获取数据库连接对象
 31         /*jdbc四大配置参数
 32          * driverClassName(与使用的数据库对应):com.mysql.jdbc.Driver
 33          * url:(Java连接数据库的地址,非http协议的url)jdbc:mysql://localhost:3306/库名
 34          * user:数据库用户名
 35          * password:数据库密码
 36          */
 37         String url="jdbc:mysql://localhost:3306/test";
 38         String user="root";
 39         String password="920346";
 40         Connection _conn=DriverManager.getConnection(url, user, password);
 41         return _conn;
 42     }
 43     
 44     public static void sqlDemo(Connection conn) throws SQLException {
 45         /*发送sql语句需要使用Statement对象,语句是正常的sql语句,注意不要加;结束
 46          * 增删改语句的发送使用executeUpdate();返回受影响行数
 47          */
 48         Statement stat=conn.createStatement();
 49         String sql="INSERT INTO test1 VALUES(2,3)";
 50         int l=stat.executeUpdate(sql);
 51         sql="UPDATE test1 SET num1=2 WHERE num1=1";
 52         l=stat.executeUpdate(sql);
 53         sql="DELETE FROM test1 WHERE num1=2";
 54         l=stat.executeUpdate(sql);
 55         System.out.println(l);
 56     }
 57 
 58     private static void queryDemo(Connection conn) throws SQLException {
 59         /*查询语句和上面的增删改的不同在于返回值:
 60          * 1、查询返回结果集;其他返回影响行数
 61          * 2、查询使用的是executeQuery();其他使用executeUpdate()
 62          */
 63         /*在创建语句发送器对象时,就已经决定了获取的结果集对象的特性,可以通过参数进行设置
 64          * 默认只能向下移动,即执行next()
 65          */
 66         Statement stat=conn.createStatement();
 67         String sql="SELECT * FROM test1";
 68         /*查询得到的结果集对象就是对数据表的抽象,是一张表,有行有列,对结果集的操作就是对行和列的操作
 69          * 对行的操作就是定位、移动和获取行数                --》结果集光标
 70          * 对列的操作就是获取列的信息(列数/类型),获取列的值    --》元数据
 71          */
 72         ResultSet rs=stat.executeQuery(sql);
 73         while(rs.next()){
 74             int num1=rs.getInt("num1");
 75             int num2=rs.getInt(2);
 76             System.out.println("num1="+num1+",num2="+num2);
 77         }
 78         
 79         //数据库连接也是一种资源,使用之后必须关闭,而且上面的三个对象都要关闭
 80         rs.close();
 81         stat.close();
 82         conn.close();
 83     }
 84 
 85     //sql代码书写规范:包括异常处理
 86     public static void sqlDemo2(){
 87         Connection conn=null;
 88         Statement stat=null;
 89         try{
 90             conn=connection();
 91             stat=conn.createStatement();
 92             String sql="INSERT INTO test1 VALUES(2,3)";
 93             int l=stat.executeUpdate(sql);
 94             sql="UPDATE test1 SET num1=2 WHERE num1=1";
 95             l=stat.executeUpdate(sql);
 96             sql="DELETE FROM test1 WHERE num1=2";
 97             l=stat.executeUpdate(sql);
 98             System.out.println(l);
 99         }catch(Exception e){
100             throw new RuntimeException();
101         }finally{
102             //防止空指针异常
103             try{
104                 if(stat!=null)
105                     stat.close();
106                 if(conn!=null)
107                     conn.close();
108             }catch(SQLException e){
109                 throw new RuntimeException();
110             }
111         }
112     }
113 }                                                        
JDBC第一例

上面的查询使用的是Statement对象,但是有一个缺点就是可能存在Sql攻击德尔问题,可以使用PreapredStatement对象最为替代,

  1 import java.io.IOException;
  2 import java.sql.Connection;
  3 import java.sql.DriverManager;
  4 import java.sql.PreparedStatement;
  5 import java.sql.ResultSet;
  6 import java.sql.SQLException;
  7 import java.sql.Statement;
  8 
  9 import org.junit.Test;
 10 
 11 
 12 /**
 13  * PreapredStatement的使用:
 14  * 防SQL攻击
 15  * @author cxf
 16  *
 17  */
 18 public class Demo2 {
 19     /**
 20      * 登录
 21      * 使用username和password去查询数据
 22      * 若查出结果集,说明正确!返回true
 23      * 若查出不出结果,说明用户名或密码错误,返回false
 24      * @param username
 25      * @param password
 26      * @return
 27      * @throws Exception 
 28      */
 29     public boolean login(String username, String password) throws Exception {
 30         /*
 31          * 一、得到Connection
 32          * 二、得到Statement
 33          * 三、得到ResultSet
 34          * 四、rs.next()返回的是什么,我们就返回什么
 35          */
 36         // 准备四大参数
 37         String driverClassName = "com.mysql.jdbc.Driver";
 38         String url = "jdbc:mysql://localhost:3306/test";
 39         String mysqlUsername = "root";
 40         String mysqlPassword = "920346";
 41         // 加载驱动类
 42         Class.forName(driverClassName);
 43         // 得到Connection
 44         Connection con = DriverManager.getConnection(url, mysqlUsername, mysqlPassword);
 45         
 46         // 得到Statement
 47         Statement stmt = con.createStatement();
 48         
 49         // 给出sql语句,调用stmt的executeQuery(),得到ResultSet
 50         String sql = "select * from j_stu where username='" + username + "' and password='" + password + "'";
 51         System.out.println(sql);
 52         ResultSet rs = stmt.executeQuery(sql);
 53         
 54         return rs.next();
 55     }
 56     
 57     /**
 58      * SQL攻击!
 59      * @throws Exception
 60      */
 61     @Test
 62     public void fun1() throws Exception {
 63         //select * from t_user where username='a' or 'a'='a' and password='a' or 'a'='a'
 64         String username = "a' or 'a'='a";
 65         String password = "a' or 'a'='a";
 66         boolean bool = login(username, password);
 67         System.out.println(bool);
 68     }
 69     
 70     public boolean login2(String username, String password) throws Exception {
 71         /*
 72          * 一、得到Connection
 73          * 二、得到Statement
 74          * 三、得到ResultSet
 75          * 四、rs.next()返回的是什么,我们就返回什么
 76          */
 77         // 准备四大参数
 78         String driverClassName = "com.mysql.jdbc.Driver";
 79         String url = "jdbc:mysql://localhost:3306/test?useServerPrepStmts=true&cachePrepStmts=true";
 80         String mysqlUsername = "root";
 81         String mysqlPassword = "920346";
 82         // 加载驱动类
 83         Class.forName(driverClassName);
 84         // 得到Connection
 85         Connection con = DriverManager.getConnection(url, mysqlUsername, mysqlPassword);
 86         
 87         ///////////////////////////////////////
 88         ///////////////////////////////////////
 89         
 90         
 91         /*
 92          * 一、得到PreparedStatement
 93          * 1. 给出sql模板:所有的参数使用?来替代
 94          * 2. 调用Connection方法,得到PreparedStatement
 95          */
 96         String sql = "select * from j_stu where username=? and password=?";
 97         PreparedStatement pstmt = con.prepareStatement(sql);
 98         
 99         /*
100          * 二、为参数赋值
101          */
102         pstmt.setString(1, username);//给第1个问号赋值,值为username
103         pstmt.setString(2, password);//给第2个问号赋值,值为password
104         
105         ResultSet rs = pstmt.executeQuery();//调用查询方法,向数据库发送查询语句
106         
107         //重复使用赋值,需要关闭上次的结果流,并清空原设置
108         rs.close();
109         pstmt.clearParameters();
110         
111         pstmt.setString(1, "liSi");
112         pstmt.setString(2, "123");
113         rs = pstmt.executeQuery();//调用查询方法,向数据库发送查询语句
114         
115         return rs.next();
116     }
117     
118     @Test
119     public void fun2() throws Exception {
120         //select * from t_user where username='a' or 'a'='a' and password='a' or 'a'='a'
121         String username = "zhangSan";
122         String password = "123";
123         boolean bool = login2(username, password);
124         System.out.println(bool);
125     }
126     
127     /**
128      * 测试JdbcUtils.getConnection()
129      * @throws SQLException 
130      * @throws ClassNotFoundException 
131      * @throws IOException 
132      */
133     @Test
134     public void fun3() throws SQLException {
135         Connection con = JdbcUtils.getConnection();
136         System.out.println(con);
137         Connection con1 = JdbcUtils.getConnection();
138         System.out.println(con1);
139     }
140 }
使用PreapredStatement防止sql攻击
 1 import java.sql.Connection;
 2 import java.sql.SQLException;
 3 
 4 import org.junit.Test;
 5 
 6 public class Demo5 {
 7     /*jdbc中使用事务的演示:转账
 8      * !!!事务是由连接对象管理,所以事务过程必须使用同一个连接对象
 9      */
10     public void transfers(String from,String to,Double money){
11         Connection conn=null;
12         try{
13             conn=JdbcUtils.getConnection();
14             //开启事务
15             conn.setAutoCommit(false);
16             //执行事务内容
17             AccountDao dao=new AccountDao();
18             dao.updateBalance(conn,from, -money);
19             dao.updateBalance(conn,to, money);
20             //提交事务
21             conn.commit();
22             conn.close();
23         }catch(Exception e){
24             try {
25                 conn.rollback();
26                 conn.close();
27             } catch (SQLException e1) {
28                 throw new RuntimeException(e);
29             }
30         }
31     }
32     @Test
33     public void fun1(){
34         transfers("zs","lisi",100.00);
35     }
36 }
事务管理

从上面的基础代码可以看出有三个对象非常重要:Connection,Statement/PreparedStatement,ResultSet.还有就是注册驱动有多种方式,上面使用的是推荐用法。

以上就是JDBC的基本使用,但是也存在一些问题,

①数据库连接使用完之后需要释放,如果经常需要连接影响性能。

②数据库的使用代码有很多都是重复的,例如获取Connection对象,异常处理等。

③对查询结果集Result对象的处理

针对上面问题的解决方案:

①使用连接池代替原始的数据库连接,连接池就是一种装饰者模式,对连接对象的close()进行增强。

 1 import java.beans.PropertyVetoException;
 2 import java.sql.Connection;
 3 import java.sql.SQLException;
 4 
 5 import org.apache.commons.dbcp.BasicDataSource;
 6 import org.junit.Test;
 7 
 8 import com.mchange.v2.c3p0.ComboPooledDataSource;
 9 
10 public class Demo6 {
11     /*使用数据库连接池获取连接对象,连接池的配置还可以在配置文件中作为资源进行配置,称为JNDI,
12      * 1、DBCP连接池
13      * 2、C3P0连接池
14      */
15     @Test
16     public void fun1() throws SQLException{
17         //数据库连接池是装饰者模式,是对Connection对象进行增强,
18         //获取连接池对象
19         BasicDataSource dataSource=new BasicDataSource();
20         //配置连接参数,因为连接池也要依靠四大参数连接数据库,并且也需要使用数据库驱动
21         dataSource.setDriverClassName("com.mysql.jdbc.Driver");
22         dataSource.setUrl("jdbc:mysql://localhost:3306/test");
23         dataSource.setUsername("root");
24         dataSource.setPassword("920346");
25         //配置池参数:有默认值,
26         dataSource.setMaxActive(20);    //最大活动连接数
27         dataSource.setMaxIdle(3);        //最大空闲连接数
28         
29         //获取连接对象
30         Connection conn=dataSource.getConnection();
31         System.out.println(conn.getClass().getName());
32         
33         //注意这里的close()被增强,不是关闭连接,而是将连接对象归还连接池
34         conn.close();
35     }
36     
37     @Test
38     public void fun2() throws SQLException, PropertyVetoException{
39         //获取连接池对象,和上面操作相似,只是名字有所不同
40         ComboPooledDataSource dataSource=new ComboPooledDataSource();
41         
42         //注意方法名和上面不同
43         dataSource.setDriverClass("com.mysql.jdbc.Driver");
44         dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
45         dataSource.setUser("root");
46         dataSource.setPassword("920346");
47         
48         //配置池参数:有默认值,
49         dataSource.setAcquireIncrement(5);
50         dataSource.setInitialPoolSize(20);
51         
52         //获取连接对象
53         Connection conn=dataSource.getConnection();
54         System.out.println(conn.getClass().getName());
55         
56         //注意这里的close()被增强,不是关闭连接,而是将连接对象归还连接池
57         conn.close();
58     }
59     @Test
60     public void fun3() throws SQLException{
61         /*c3p0连接池的配置参数可以直接写在配置文件中,
62          * 只要将配置文件保存在类路径下即可在创建类时自动寻找
63          * 注意:默认情况下使用的是默认配置,如果在代码中在进行配置就会将配置文件中的覆盖
64          */
65         ComboPooledDataSource dataSource=new ComboPooledDataSource();
66         
67         Connection conn=dataSource.getConnection();
68         System.out.println(conn.getClass().getName());
69         
70         conn.close();
71     }
72     public void fun4() throws SQLException{
73         //在配置文件中可以有多个配置,如果不使用默认配置二使用其他配置,只要将节点名作为参数传入即可
74         ComboPooledDataSource dataSource=new ComboPooledDataSource("oracle-config");
75         
76         Connection conn=dataSource.getConnection();
77         System.out.println(conn.getClass().getName());
78         
79         conn.close();
80     }
81 }
数据库连接池的使用

②使用Apache Commons dbUtils包进行处理

③使用Apache Commons dbUtils包将结果集与java中的对象,集合等结构进行操作

对Apache Commons dbUtils包的说明参见

http://www.jb51.net/article/61886.htm

http://lavasoft.blog.51cto.com/62575/222771/

http://www.cnblogs.com/xdp-gacl/p/4007225.html

原文地址:https://www.cnblogs.com/songfeilong2325/p/4808526.html