当前位置:Gxlcms > 数据库问题 > JDBC入门

JDBC入门

时间:2021-07-01 10:21:17 帮助过:29人阅读

package com.boe.jdbc; 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 9 import com.mysql.jdbc.Driver; 10 11 public class ConnectionDemo { 12 13 public static void main(String[] args) throws SQLException { 14 //1 注册数据库驱动 15 DriverManager.registerDriver(new Driver()); 16 //2 获取数据库连接 17 Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2", "root", "2688"); 18 //3 创建传输器 19 Statement stmt=conn.createStatement(); 20 //4 创建sql会返回结果 21 ResultSet rs=stmt.executeQuery("SELECT *FROM dept"); 22 //5 遍历结果 23 while(rs.next()){//next()会移动行的光标,如果移动到的行有数据返回true,否则返回false,初始化位置在第一行前面 24 //获取表字段数据 25 int id=rs.getInt("id"); 26 String name=rs.getString("name"); 27 System.out.println("id="+id+",name="+name); 28 } 29 //6 关闭资源 后创建的先关闭 30 rs.close();//不关闭,数据库数据会留在内存 31 stmt.close();//这个关闭会自动关闭rs 32 conn.close(); 33 34 } 35 36 }

控制台输出情况。

技术图片

优化JDBC连接方式

以上为最原始的方式,但是存在问题,即DriverManager会注册两次,因为底层Driver有一个静态方法也会注册一次,因此这里采用反射加载驱动类来实现注册,具体参考代码。

底层静态代码块加载后会注册一次。

技术图片

 1 package com.boe.jdbc;
 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 
 9 import com.mysql.jdbc.Driver;
10 
11 public class ConnectionDemo1 {
12 
13     public static void main(String[] args) {
14         //1 注册数据库驱动
15         //问题1 手动注册了一次,底层代码也注册了一次,注册了两次驱动实际上,只需要注册一次即可
16         //问题2 包名和代码绑定死,如果更换数据库,需要修改包名
17         //DriverManager.registerDriver(new Driver());
18         //定义成员变量
19         Connection conn=null;
20         Statement stmt=null;
21         ResultSet rs=null;
22         try {
23             Class.forName("com.mysql.jdbc.Driver");
24             //利用反射API获取一次Driver类,会自动执行一次Driver类中的静态方法
25             //2 获取数据库连接
26             //Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2", "root", "2688");
27             //下面的连接方式写法也可以,参考文档26连接器
28             conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2?user=root&password=2688");
29             //3 创建传输器
30             stmt=conn.createStatement();
31             //4 创建sql会返回结果
32             rs=stmt.executeQuery("SELECT * FROM dept");
33             //5 遍历结果
34             while(rs.next()){//next()会移动行的光标,如果移动到的行有数据返回true,否则返回false,初始化位置在第一行前面
35                 //获取表字段数据
36                 int id=rs.getInt("id");
37                 String name=rs.getString("name");
38                 System.out.println("id="+id+",name="+name);
39             }
40         } catch (Exception e) {
41             e.printStackTrace();
42             throw new RuntimeException(e);
43         }finally{
44             //6 关闭资源  后创建的先关闭
45             try {
46                 if(rs!=null){
47                     rs.close();//不关闭,数据库数据会留在内存
48                 }
49             } catch (SQLException e) {
50                 e.printStackTrace();
51                 //可以选择抛出运行时异常,不会打断程序
52                 throw new RuntimeException(e);
53             }finally{
54                 rs=null;
55             }            
56             try {
57                 if(stmt!=null){
58                     stmt.close();//这个关闭会自动关闭rs                    
59                 }
60             } catch (SQLException e) {
61                 e.printStackTrace();
62                 throw new RuntimeException(e);
63             }finally{
64                 stmt=null;
65             }            
66             try {
67                 if(conn!=null){
68                     conn.close();                    
69                 }
70             } catch (SQLException e) {
71                 e.printStackTrace();
72                 throw new RuntimeException(e);
73             }finally{            
74                 conn=null;
75             }
76         }        
77     }
78 }

使用优化后的JDBC实现CRUB操作

以下简单的实现了CRUB操作,使用优化后注册方式。

  1 package com.boe.jdbc;
  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 
  9 import org.junit.Test;
 10 
 11 import com.boe.utils.JDBCUtils;
 12 
 13 public class ConnectionDemo3 {
 14     //添加操作
 15     @Test
 16     public void add(){
 17         Connection conn=null;
 18         Statement stmt=null;
 19         try {
 20             //1 注册数据库驱动
 21             Class.forName("com.mysql.jdbc.Driver");
 22             //2 创建数据库连接
 23             conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2?user=root&password=2688");
 24             //3 获取传输器
 25             stmt=conn.createStatement();
 26             //4 输出sql 获取结果集
 27             int i=stmt.executeUpdate("INSERT INTO dept Values(null,‘文娱部‘)");
 28             if(i>0){
 29                 System.out.println("插入成功,受到影响的行数为:"+i+"行");
 30             }
 31         } catch (Exception e) {
 32             e.printStackTrace();
 33         }finally{
 34             //后创建的先关闭
 35             try {
 36                 if(stmt!=null){
 37                     stmt.close();                
 38                 }
 39             } catch (SQLException e) {
 40                 e.printStackTrace();
 41             }finally{
 42                 stmt=null;
 43             }
 44             try {
 45                 if(conn!=null){
 46                     conn.close();    
 47                 }
 48             } catch (SQLException e) {
 49                 e.printStackTrace();
 50             }finally{
 51                 conn=null;
 52             }
 53         }
 54     }
 55     
 56     //更新数据的方法
 57     @Test
 58     public void update(){
 59         Connection conn=null;
 60         Statement stmt=null;
 61         try{
 62             Class.forName("com.mysql.jdbc.Driver");
 63             conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2?user=root&password=2688");
 64             stmt=conn.createStatement();
 65             int i=stmt.executeUpdate("UPDATE dept SET name=‘IT部门‘ WHERE id=6");
 66             if(i>0){
 67                 System.out.println("更新成功,受到影响的行数为:"+i+"行");                
 68             }
 69         }catch(Exception e){
 70             e.printStackTrace();
 71         }finally{
 72             //后创建的先关闭
 73             try {
 74                 if(stmt!=null){
 75                     stmt.close();                
 76                 }
 77             } catch (SQLException e) {
 78                 e.printStackTrace();
 79             }finally{
 80                 stmt=null;
 81             }
 82             try {
 83                 if(conn!=null){
 84                     conn.close();    
 85                 }
 86             } catch (SQLException e) {
 87                 e.printStackTrace();
 88             }finally{
 89                 conn=null;
 90             }            
 91         }
 92     }
 93     
 94     //删除数据
 95     @Test
 96     public void delete(){
 97         Connection conn=null;
 98         Statement stmt=null;
 99         try{
100             conn=JDBCUtils.getConnection();
101             stmt=conn.createStatement();
102             int i=stmt.executeUpdate("DELETE FROM dept WHERE id=8");
103             if(i>0){
104                 System.out.println("删除成功,受到影响的行数为:"+i+"行");                
105             }
106         }catch(Exception e){
107             e.printStackTrace();
108         }finally{
109             JDBCUtils.closeConnection(conn, stmt, null);
110         }
111     }
112 }

生成工具类DBUtils

在使用的过程中发现很多代码需要重复写,如类加载和获取连接,以及关闭资源等,这些反复书写的代码可以提取出来,写到一个工具类里面,这里将创建连接需要的驱动类名,url,用户名和密码都保存在了一个properties文件里面,这样如果需要更改数据库就只需要修改配置文件即可。

 1 package com.boe.utils;
 2 
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileNotFoundException;
 6 import java.io.IOException;
 7 import java.sql.Connection;
 8 import java.sql.DriverManager;
 9 import java.sql.ResultSet;
10 import java.sql.SQLException;
11 import java.sql.Statement;
12 import java.util.Properties;
13 
14 //工厂类:不允许创建对象,方法为静态方法
15 public class JDBCUtils {
16     //不允许创建对象,构造方法私有化    
17     private JDBCUtils(){
18         
19     }
20     //prop变成静态,代表只创建一次
21     private static Properties prop=new Properties();
22     static{
23         try {
24             prop.load(new FileInputStream(new File(JDBCUtils.class.getClassLoader().getResource("conf.properties").getPath())));
25         } catch (FileNotFoundException e) {
26             e.printStackTrace();
27         } catch (IOException e) {
28             e.printStackTrace();
29         }
30     }
31     //写静态方法
32     public static Connection getConnection() throws Exception{
33         //将配置信息加载prop
34         //Properties prop=new Properties();
35         //prop.load(new FileInputStream(new File(JDBCUtils.class.getClassLoader().getResource("conf.properties").getPath())));
36         //获取prop里的内容
37         String driver=prop.getProperty("driver");
38         String url=prop.getProperty("url");
39         String user=prop.getProperty("user");
40         String pwd=prop.getProperty("password");
41         //Class.forName("com.mysql.jdbc.Driver");
42         Class.forName(driver);
43         //2 创建数据库连接
44         //return DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2?user=root&password=2688");
45         return DriverManager.getConnection(url,user,pwd);
46     }
47     public static void closeConnection(Connection conn,Statement stmt,ResultSet rs){
48         //后创建的先关闭
49         try {
50             if(rs!=null){
51                 rs.close();                
52             }
53         } catch (SQLException e) {
54             e.printStackTrace();
55         }finally{
56             rs=null;
57         }
58         try {
59             if(stmt!=null){
60                 stmt.close();                
61             }
62         } catch (SQLException e) {
63             e.printStackTrace();
64         }finally{
65             stmt=null;
66         }
67         try {
68             if(conn!=null){
69                 conn.close();    
70             }
71         } catch (SQLException e) {
72             e.printStackTrace();
73         }finally{
74             conn=null;
75         }
76     }
77 }

使用工具类完成登录模拟

在完成工具类的泛化后,接下来使用它可以完成一个简单的登录案例,其中引出PreparedStatement和SQL注入,

如果使用Statement,会有SQL注入的风险,即SQL后台拼接后如果参数里有SQL关键字,可能导致整条SQL语义的变化导致不需要输入密码也可以登录的情况,如用户名后加上‘ #,或者密码里加上‘OR ‘ 1=1。这样的情况下,PreparedStatement就应用而生,它是Statement的一个子接口,使用它将先将SQL进行预编译,参数只是用?占位符来代替,后面传入参数也只是将其作为文本来处理,不会导致语义的变化。

 1 package com.boe.jdbc;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import java.sql.Statement;
 7 import java.util.Scanner;
 8 
 9 import com.boe.utils.JDBCUtils;
10 
11 //登录
12 public class Login {
13     //用户输入用户名和密码,和数据库中的进行比较,如果匹配则提示登录成功,否则提示失败
14     public static void main(String[] args) {
15         //获取控制台输入的用户名和密码
16         Scanner scan=new Scanner(System.in);
17         System.out.println("请输入用户名:");
18         String user=scan.nextLine();
19         System.out.println("请输入密码:");
20         String pwd=scan.nextLine();
21         //测试是否正确
22         testLogin( user,pwd);        
23         //testPreparedStatementLogin(user,pwd);
24         
25     }
26     /**
27      * 访问数据库,使用Preparedstatement根据用户名和密码进行访问
28      * @param user
29      * @param pwd
30      */
31     private static void testPreparedStatementLogin(String user, String pwd) {
32         Connection conn=null;
33         PreparedStatement ps=null;
34         ResultSet rs=null;
35         try {
36             conn=JDBCUtils.getConnection();
37             String sql="SELECT * FROM user WHERE username=? AND password=? ";
38             ps=conn.prepareStatement(sql);
39             ps.setString(1, user);
40             ps.setString(2, pwd);
41             rs=ps.executeQuery();
42             if(rs.next()){
43                 System.out.println("登录成功");
44             }else{
45                 System.out.println("登录失败");
46             }
47         } catch (Exception e) {
48             e.printStackTrace();
49         }finally{
50             //PreparedStatement继承自Statement接口,所以可以直接用
51             JDBCUtils.closeConnection(conn, ps, rs);
52         }
53             
54     }
55     /**
56      * 访问数据库,根据用户名和密码进行访问
57      * @param user
58      * @param pwd
59      */
60     private static void testLogin(String user, String pwd) {
61         Connection conn=null;
62         Statement stmt=null;
63         ResultSet rs=null;
64         try {
65             conn=JDBCUtils.getConnection();
66             stmt=conn.createStatement();
67             String sql="SELECT * FROM user WHERE username=‘"+user+"‘ AND password=‘"+pwd+"‘";
68             rs=stmt.executeQuery(sql);
69             //打印sql,查看sql注入攻击
70             System.out.println(sql);
71             if(rs.next()){
72                 System.out.println("登录成功");
73             }else{
74                 System.out.println("登录失败");
75             }
76         } catch (Exception e) {
77             e.printStackTrace();
78         }finally{
79             JDBCUtils.closeConnection(conn, stmt, rs);
80         }
81     }
82     
83 }

不使用预编译的结果,可以看到可以sql注入。

技术图片

技术图片

批量处理

在介绍完上面的基本操作后,JDBC还提供批量处理的API,可以实现SQL批量处理,其有两种选择,一个是使用Statement的批处理,一个是使用PreparedStatement的批处理,两者各有优缺点。前者的话就是可以放入不同结构的SQL,但是没有预编译效率低,后者是有预编译效率高,但是更适合有相同结构但是参数不同的SQL。

Statement实现批处理

 1 package com.boe.batch;
 2 
 3 import java.sql.Connection;
 4 import java.sql.Statement;
 5 
 6 import com.boe.utils.JDBCUtils;
 7 
 8 //批处理
 9 /*
10  *   create table t1(id int primary key auto_increment,name varchar(20));
11  *   insert into t1 values(null,‘鸣人‘);
12  *   insert into t1 values(null,‘向日‘);
13  *   insert into t1 values(null,‘卡卡西‘);
14  *   insert into t1 values(null,‘大蛇‘);
15  *   
16  * */
17 public class StatementBatch {
18 
19     public static void main(String[] args) {
20         Connection conn=null;
21         Statement stmt=null;
22         try{
23             conn=JDBCUtils.getConnection();
24             stmt=conn.createStatement();
25             stmt.addBatch("create table t1(id int primary key auto_increment,name varchar(20))");
26             stmt.addBatch(" insert into t1 values(null,‘鸣人‘)");
27             stmt.addBatch(" insert into t1 values(null,‘向日‘)");
28             stmt.addBatch(" insert into t1 values(null,‘卡卡西‘)");
29             stmt.addBatch(" insert into t1 values(null,‘大蛇‘)");
30             int[] arr=stmt.executeBatch();
31             System.out.println(arr.toString());
32             System.out.println("批处理执行完成");
33         }catch(Exception e){
34             e.printStackTrace();
35         }finally{
36             JDBCUtils.closeConnection(conn, stmt, null);
37         }
38     }
39 
40 }

技术图片

技术图片

PreparedStatement实现批处理

 1 package com.boe.batch;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 
 6 import com.boe.utils.JDBCUtils;
 7 
 8 /*
 9  *   create table t1(id int primary key auto_increment,name varchar(20));
10  *   insert into t1 values(null,‘鸣人‘);
11  *   insert into t1 values(null,‘向日‘);
12  *   insert into t1 values(null,‘卡卡西‘);
13  *   insert into t1 values(null,‘大蛇‘);
14  *   
15  * */
16 public class PrepareBatch {
17 
18     public static void main(String[] args) {
19         //PrepareStatement比较适合sql主干一致的
20         Connection conn=null;
21         PreparedStatement ps=null;
22         try{
23             conn=JDBCUtils.getConnection();
24             ps=conn.prepareStatement("INSERT INTO t1 values(null,?)");
25             //添加批处理
26             for(int i=1;i<1000;i++){
27                 ps.setString(1, "小明"+i);
28                 ps.addBatch();
29                 if(i%100==0){
30                     //每隔1000条执行一次
31                     ps.executeBatch();
32                     //执行完的批处理可以清空
33                     ps.clearBatch();
34                     System.out.println("第"+i/100+"批处理完成");
35                 }
36             }
37             //批量处理,收尾
38             ps.executeBatch();
39             System.out.println("全部处理完成");
40         }catch(Exception e){
41             e.printStackTrace();
42         }finally{
43             JDBCUtils.closeConnection(conn, ps, null);
44         }
45     }
46 
47 }

技术图片 技术图片

数据库连接池

在大量数据库连

人气教程排行