JDBC学习小结

一、JDBC基础

连接数据的步骤:

1.注册驱动 :Class.forName(“com.mysql.jdbc.Driver”) 推荐这种方式,不会对具体的驱动类产生依赖;DriverManager.registerDriver(com.mysql.jdbc.Driver)
 会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖;System.setProperty(“jdbc.drivers”, “driver1:driver2”) 虽然不会对具体的驱动类产生依赖;但注册不太方便,所以很少使用。
2.建立连接(Connection) :Connection conn = DriverManager.getConnection(url, user, password);url格式: JDBC:子协议:子名称//主机名:端口/数据库名?属性名=属性值&...;User,password可以用“属性名=属性值”方式告诉数据库;其他参数如:useUnicode=true&characterEncoding=GBK。
3.创建执行SQL的语句(Statement):
4.执行语句
5.处理执行结果(ResultSet)
6.释放资源

1、注册数据库驱动的方式:

1)加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名;

 1 @Test
 2 public void testDriverManager() throws Exception{
 3     //1. 准备连接数据库的 4 个字符串.
 4     //驱动的全类名.
 5     String driverClass = "com.mysql.jdbc.Driver";
 6     //JDBC URL
 7     String jdbcUrl = "jdbc:mysql://localhost:3306/test";
 8     //user
 9     String user = "root";
10     //password
11     String password = "123456";
12
13     //2. 加载数据库驱动程序(对应的 Driver 实现类中有注册驱动的静态代码块.)
14     Class.forName(driverClass);
15
16     //3. 通过 DriverManager 的 getConnection() 方法获取数据库连接.
17     Connection connection =
18             DriverManager.getConnection(jdbcUrl, user, password);
19     System.out.println(connection);
20
21 }

2)Driver 是一个接口: 数据库厂商必须提供实现的接口. 能从其中获取数据库连接.可以通过 Driver 的实现类对象获取数据库连接.

 1 @Test
 2 public void testDriver() throws SQLException {
 3     //1. 创建一个 Driver 实现类的对象
 4     Driver driver = new com.mysql.jdbc.Driver();
 5
 6     //2. 准备连接数据库的基本信息: url, user, password
 7     String url = "jdbc:mysql://localhost:3306/test";
 8     Properties info = new Properties();
 9     info.put("user", "root");
10     info.put("password", "123456");
11
12     //3. 调用 Driver 接口的 connect(url, info) 获取数据库连接
13     Connection connection = driver.connect(url, info);
14     System.out.println(connection);
15 }

2、获取数据库连接的方式:
1)DriverManager 是驱动的管理类:1). 可以通过重载的 getConnection() 方法获取数据库连接. 较为方便,2). 可以同时管理多个驱动程序: 若注册了多个数据库连接, 则调用 getConnection(),3)方法时传入的参数不同, 即返回不同的数据库连接。

例:Connection connection = DriverManager.getConnection(jdbcUrl, user, password);

2)Driver 是一个接口: 数据库厂商必须提供实现的接口. 能从其中获取数据库连接.可以通过 Driver 的实现类对象获取数据库连接.

例:Connection connection = driver.connect(url, info);

3.创建执行SQL的语句(statement、preparedstatement):

通过 JDBC 向指定的数据表中插入一条记录. 
  a. Statement: 用于执行 SQL 语句的对象
  1). 通过 Connection 的 createStatement() 方法来获取
  2). 通过 executeUpdate(sql) 可以执行 SQL 语句.
  3). 传入的 SQL 可以是 INSRET, UPDATE 或 DELETE. 但不能是 SELECT
 
  b. Connection、Statement 都是应用程序和数据库服务器的连接资源. 使用后一定要关闭.
   需要在 finally 中关闭 Connection 和 Statement 对象. 
   
  c. 关闭的顺序是: 先关闭后获取的. 即先关闭 Statement 后关闭 Connection

示例代码如下:

 1 @Test
 2 public void testStatement() throws Exception{
 3     //1. 获取数据库连接
 4     Connection conn = null;
 5     Statement statement = null;
 6
 7     try {
 8         conn = JDBCTools.getConnection();
 9
10         //3. 准备插入的 SQL 语句
11         String sql = null;
12
13                //sql = "INSERT INTO customers (NAME, EMAIL, BIRTH) " +
14                    //"VALUES(‘XYZ‘, ‘[email protected]‘, ‘1990-12-12‘)";
15               //sql = "DELETE FROM customers WHERE id = 1";
16         sql = "UPDATE customers SET name = ‘TOM‘ " +
17                 "WHERE id = 4";
18         System.out.println(sql);
19
20           //4. 执行插入.
21           //1). 获取操作 SQL 语句的 Statement 对象:
22          //调用 Connection 的 createStatement() 方法来获取
23           statement = conn.createStatement();
24
25          //2). 调用 Statement 对象的 executeUpdate(sql) 执行 SQL 语句进行插入
26           statement.executeUpdate(sql);
27     } catch (Exception e) {
28         e.printStackTrace();
29     } finally{
30         JDBCTools.release(statement,conn);
31     }     

4.处理执行结果(ResultSet):
ResultSet: 结果集. 封装了使用 JDBC 进行查询的结果. 
   a. 调用 Statement 对象的 executeQuery(sql) 可以得到结果集.
   b. ResultSet 返回的实际上就是一张数据表. 有一个指针指向数据表的第一样的前面.可以调用 next() 方法检测下一行是否有效. 若有效该方法返回 true, 且指针下移. 相当于Iterator 对象的 hasNext() 和 next() 方法的结合体
   c. 当指针对位到一行时, 可以通过调用 getXxx(index) 或 getXxx(columnName),获取每一列的值. 例如: getInt(1), getString("name")
   d. ResultSet 当然也需要进行关闭.

示例代码如下:

 1 @Test
 2 public void testResultSet(){
 3     //获取 id=4 的 customers 数据表的记录, 并打印
 4
 5     Connection conn = null;
 6     Statement statement = null;
 7     ResultSet rs = null;
 8
 9     try {
10         //1. 获取 Connection
11         conn = JDBCTools.getConnection();
12         System.out.println(conn);
13
14         //2. 获取 Statement
15         statement = conn.createStatement();
16         System.out.println(statement);
17
18         //3. 准备 SQL
19         String sql = "SELECT id, name, email, birth " +
20                     "FROM customers";
21
22         //4. 执行查询, 得到 ResultSet
23         rs = statement.executeQuery(sql);
24         System.out.println(rs);
25
26         //5. 处理 ResultSet
27         while(rs.next()){
28             int id = rs.getInt(1);
29             String name = rs.getString("name");
30             String email = rs.getString(3);
31             Date birth = rs.getDate(4);
32
33             System.out.println(id);
34             System.out.println(name);
35             System.out.println(email);
36             System.out.println(birth);
37         }
38
39     } catch (Exception e) {
40         e.printStackTrace();
41     } finally{
42         //6. 关闭数据库资源.
43         JDBCTools.release(rs, statement, conn);
44     }
45
46 }

JDBC工具模板(JDBCTools)配置如下:

 1 import java.io.InputStream;
 2 import java.sql.Connection;
 3 import java.sql.DriverManager;
 4 import java.sql.ResultSet;
 5 import java.sql.SQLException;
 6 import java.sql.Statement;
 7 import java.util.Properties;
 8
 9 /**
10  * 操作 JDBC 的工具类. 其中封装了一些工具方法 Version 1
11  */
12 public class JDBCTools {
13
14     public static void release(ResultSet rs,
15             Statement statement, Connection conn) {
16         if(rs != null){
17             try {
18                 rs.close();
19             } catch (SQLException e) {
20                 e.printStackTrace();
21             }
22         }
23
24
25         if (statement != null) {
26             try {
27                 statement.close();
28             } catch (Exception e2) {
29                 e2.printStackTrace();
30             }
31         }
32
33         if (conn != null) {
34             try {
35                 conn.close();
36             } catch (Exception e2) {
37                 e2.printStackTrace();
38             }
39         }
40     }
41
42     /**
43      * 关闭 Statement 和 Connection
44      * @param statement
45      * @param conn
46      */
47     public static void release(Statement statement, Connection conn) {
48         if (statement != null) {
49             try {
50                 statement.close();
51             } catch (Exception e2) {
52                 e2.printStackTrace();
53             }
54         }
55
56         if (conn != null) {
57             try {
58                 conn.close();
59             } catch (Exception e2) {
60                 e2.printStackTrace();
61             }
62         }
63     }
64
65     /**
66      * 1. 获取连接的方法. 通过读取配置文件从数据库服务器获取一个连接.
67      *
68      * @return
69      * @throws Exception
70      */
71     public static Connection getConnection() throws Exception {
72         // 1. 准备连接数据库的 4 个字符串.
73         // 1). 创建 Properties 对象
74         Properties properties = new Properties();
75
76         // 2). 获取 jdbc.properties 对应的输入流
77         InputStream in = JDBCTools.class.getClassLoader().getResourceAsStream(
78                 "jdbc.properties");
79
80         // 3). 加载 2) 对应的输入流
81         properties.load(in);
82
83         // 4). 具体决定 user, password 等4 个字符串.
84         String user = properties.getProperty("user");
85         String password = properties.getProperty("password");
86         String jdbcUrl = properties.getProperty("jdbcUrl");
87         String driver = properties.getProperty("driver");
88
89         // 2. 加载数据库驱动程序(对应的 Driver 实现类中有注册驱动的静态代码块.)
90         Class.forName(driver);
91
92         // 3. 通过 DriverManager 的 getConnection() 方法获取数据库连接.
93         return DriverManager.getConnection(jdbcUrl, user, password);
94     }
95
96 }

1 driver=com.mysql.jdbc.Driver
2 jdbcUrl=jdbc:mysql://localhost:3306/test
3 user=root
4 password=123456

二、实现数据库增删改查

1.创立数据库表 examstudent;

 1 /*
 2 Navicat MySQL Data Transfer
 3
 4 Source Server         : localhost
 5 Source Server Version : 50524
 6 Source Host           : localhost:3306
 7 Source Database       : examstudent
 8
 9 Target Server Type    : MYSQL
10 Target Server Version : 50524
11 File Encoding         : 65001
12
13 Date: 2015-06-27 15:49:22
14 */
15
16 SET FOREIGN_KEY_CHECKS=0;
17
18 -- ----------------------------
19 -- Table structure for examstudent
20 -- ----------------------------
21 DROP TABLE IF EXISTS `examstudent`;
22 CREATE TABLE `examstudent` (
23   `flowid` int(11) NOT NULL,
24   `type` int(11) DEFAULT NULL,
25   `idcard` varchar(18) DEFAULT NULL,
26   `examcard` varchar(15) DEFAULT NULL,
27   `studentname` varchar(20) DEFAULT NULL,
28   `location` varchar(20) DEFAULT NULL,
29   `grade` int(11) DEFAULT NULL,
30   PRIMARY KEY (`flowid`)
31 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.向数据库中添加如下数据

3. 在 eclipse 中建立 java 程序:输入身份证号或准考证号可以查询到学生的基本信息。

4.完成学生信息的删除功能

示例代码如下:

jdbc.properties

1 user=root
2 password=123456
3 driverClass=com.mysql.jdbc.Driver
4 url=jdbc:mysql://localhost:3306/examstudent

student.java

  1 package com.atguigu.jdbc;
  2
  3 public class Student {
  4
  5     // 流水号
  6     private int flowId;
  7     // 考试的类型
  8     private int type;
  9     // 身份证号
 10     private String idCard;
 11     // 准考证号
 12     private String examCard;
 13     // 学生名
 14     private String studentName;
 15     // 学生地址
 16     private String location;
 17     // 考试分数.
 18     private int grade;
 19
 20     public int getFlowId() {
 21         return flowId;
 22     }
 23
 24     public void setFlowId(int flowId) {
 25         this.flowId = flowId;
 26     }
 27
 28     public int getType() {
 29         return type;
 30     }
 31
 32     public void setType(int type) {
 33         this.type = type;
 34     }
 35
 36     public String getIdCard() {
 37         return idCard;
 38     }
 39
 40     public void setIdCard(String idCard) {
 41         this.idCard = idCard;
 42     }
 43
 44     public String getExamCard() {
 45         return examCard;
 46     }
 47
 48     public void setExamCard(String examCard) {
 49         this.examCard = examCard;
 50     }
 51
 52     public String getStudentName() {
 53         return studentName;
 54     }
 55
 56     public void setStudentName(String studentName) {
 57         this.studentName = studentName;
 58     }
 59
 60     public String getLocation() {
 61         return location;
 62     }
 63
 64     public void setLocation(String location) {
 65         this.location = location;
 66     }
 67
 68     public int getGrade() {
 69         return grade;
 70     }
 71
 72     public void setGrade(int grade) {
 73         this.grade = grade;
 74     }
 75
 76     public Student(int flowId, int type, String idCard, String examCard,
 77             String studentName, String location, int grade) {
 78         super();
 79         this.flowId = flowId;
 80         this.type = type;
 81         this.idCard = idCard;
 82         this.examCard = examCard;
 83         this.studentName = studentName;
 84         this.location = location;
 85         this.grade = grade;
 86     }
 87
 88     public Student() {
 89         // TODO Auto-generated constructor stub
 90     }
 91
 92     @Override
 93     public String toString() {
 94         return "Student [flowId=" + flowId + ", type=" + type + ", idCard="
 95                 + idCard + ", examCard=" + examCard + ", studentName="
 96                 + studentName + ", location=" + location + ", grade=" + grade
 97                 + "]";
 98     }
 99
100 }

JDBCTools.java

  1 package cky.test;
  2
  3 import java.io.IOException;
  4 import java.io.InputStream;
  5 import java.sql.Connection;
  6 import java.sql.DriverManager;
  7 import java.sql.PreparedStatement;
  8 import java.sql.ResultSet;
  9 import java.sql.SQLException;
 10 import java.sql.Statement;
 11 import java.util.Properties;
 12
 13 public class JDBCTools {
 14
 15     /**
 16      * 执行 SQL 语句, 使用 PreparedStatement
 17      * @param sql
 18      * @param args: 填写 SQL 占位符的可变参数
 19      */
 20     public static void update(String sql, Object ... args){
 21         Connection connection = null;
 22         PreparedStatement preparedStatement = null;
 23
 24         try {
 25             connection = JDBCTools.getConnection();
 26             preparedStatement = connection.prepareStatement(sql);
 27
 28             for(int i = 0; i < args.length; i++){
 29                 preparedStatement.setObject(i + 1, args[i]);
 30             }
 31
 32             preparedStatement.executeUpdate();
 33
 34         } catch (Exception e) {
 35             e.printStackTrace();
 36         } finally{
 37             JDBCTools.releaseDB(null, preparedStatement, connection);
 38         }
 39     }
 40
 41     /**
 42      * 执行 SQL 的方法
 43      *
 44      * @param sql: insert, update 或 delete。 而不包含 select
 45      */
 46     public static void update(String sql) {
 47         Connection connection = null;
 48         Statement statement = null;
 49
 50         try {
 51             // 1. 获取数据库连接
 52             connection = getConnection();
 53
 54             // 2. 调用 Connection 对象的 createStatement() 方法获取 Statement 对象
 55             statement = connection.createStatement();
 56
 57             // 4. 发送 SQL 语句: 调用 Statement 对象的 executeUpdate(sql) 方法
 58             statement.executeUpdate(sql);
 59
 60         } catch (Exception e) {
 61             e.printStackTrace();
 62         } finally {
 63             // 5. 关闭数据库资源: 由里向外关闭.
 64             releaseDB(null, statement, connection);
 65         }
 66     }
 67
 68     /**
 69      * 释放数据库资源的方法
 70      *
 71      * @param resultSet
 72      * @param statement
 73      * @param connection
 74      */
 75     public static void releaseDB(ResultSet resultSet, Statement statement,
 76             Connection connection) {
 77
 78         if (resultSet != null) {
 79             try {
 80                 resultSet.close();
 81             } catch (SQLException e) {
 82                 e.printStackTrace();
 83             }
 84         }
 85
 86         if (statement != null) {
 87             try {
 88                 statement.close();
 89             } catch (SQLException e) {
 90                 e.printStackTrace();
 91             }
 92         }
 93
 94         if (connection != null) {
 95             try {
 96                 connection.close();
 97             } catch (SQLException e) {
 98                 e.printStackTrace();
 99             }
100         }
101
102     }
103
104     /**
105      * 获取数据库连接的方法
106      */
107     public static Connection getConnection() throws IOException,
108             ClassNotFoundException, SQLException {
109         // 0. 读取 jdbc.properties
110         /**
111          * 1). 属性文件对应 Java 中的 Properties 类 2). 可以使用类加载器加载 bin 目录(类路径下)的文件
112          */
113         Properties properties = new Properties();
114         InputStream inStream = JDBCTools.class.getClassLoader()
115                 .getResourceAsStream("jdbc.properties");
116         properties.load(inStream);
117
118         // 1. 准备获取连接的 4 个字符串: user, password, jdbcUrl, driverClass
119         String user = properties.getProperty("user");
120         String password = properties.getProperty("password");
121         String jdbcUrl = properties.getProperty("url");
122         String driverClass = properties.getProperty("driverClass");
123
124         // 2. 加载驱动: Class.forName(driverClass)
125         Class.forName(driverClass);
126
127         // 3. 调用
128         // DriverManager.getConnection(jdbcUrl, user, password)
129         // 获取数据库连接
130         Connection connection = DriverManager.getConnection(jdbcUrl, user,
131                 password);
132         return connection;
133     }
134
135 }

JDBCTest.java

  1 package cky.test;
  2
  3 import java.sql.Connection;
  4
  5 import java.sql.PreparedStatement;
  6 import java.sql.ResultSet;
  7
  8 import java.util.Scanner;
  9
 10 import org.junit.Test;
 11
 12 public class JDBCTest {
 13
 14     //得到学生的信息集
 15     public Student getStudent(String sql, Object... args) {
 16         Student stu = null;
 17
 18         Connection connection = null;
 19         PreparedStatement preparedStatement = null;
 20         ResultSet resultSet = null;
 21
 22         try {
 23             connection = JDBCTools.getConnection();
 24             preparedStatement = connection.prepareStatement(sql);
 25             for (int i = 0; i < args.length; i++) {
 26                 preparedStatement.setObject(i + 1, args[i]);
 27             }
 28             resultSet = preparedStatement.executeQuery();
 29
 30             if (resultSet.next()) {
 31                 stu = new Student();
 32                 stu.setFlowId(resultSet.getInt(1));
 33                 stu.setType(resultSet.getInt(2));
 34                 stu.setIdCard(resultSet.getString(3));
 35
 36             }
 37
 38         } catch (Exception e) {
 39             e.printStackTrace();
 40         } finally {
 41             JDBCTools.releaseDB(resultSet, preparedStatement, connection);
 42         }
 43
 44         return stu;
 45     }
 46
 47
 48     /*
 49     private Student getStudent(String sql) {
 50
 51         Student stu = null;
 52
 53         Connection connection = null;
 54         Statement statement = null;
 55         ResultSet resultSet = null;
 56
 57         try {
 58             connection = JDBCTools.getConnection();
 59             statement = connection.createStatement();
 60             resultSet = statement.executeQuery(sql);
 61
 62             if (resultSet.next()) {
 63                 stu = new Student(resultSet.getInt(1), resultSet.getInt(2),
 64                         resultSet.getString(3), resultSet.getString(4),
 65                         resultSet.getString(5), resultSet.getString(6),
 66                         resultSet.getInt(7));
 67             }
 68
 69         } catch (Exception e) {
 70             e.printStackTrace();
 71         } finally {
 72             JDBCTools.releaseDB(resultSet, statement, connection);
 73         }
 74
 75         return stu;
 76     }
 77     */
 78
 79     //打印学生信息: 若学生存在则打印其具体信息. 若不存在: 打印查无此人
 80     private void printStudent(Student student) {
 81         if (student != null) {
 82             System.out.println(student);
 83         } else {
 84             System.out.println("查无此人!");
 85         }
 86     }
 87
 88     // 从控制台读入一个整数, 确定要查询的类型; @return: 1. 用身份证查询. 2. 用准考证号查询 其他的无效. 并提示请用户重新输入.
 89     private int getSearchTypeFromConsole() {
 90
 91         System.out.print("请输入查询类型: 1. 用身份证查询. 2. 用准考证号查询 ");
 92
 93         Scanner scanner = new Scanner(System.in);
 94         int type = scanner.nextInt();
 95
 96         if (type != 1 && type != 2) {
 97             System.out.println("输入有误请重新输入!");
 98             throw new RuntimeException();
 99         }
100
101         return type;
102     }
103
104     //从控制台输入学生的信息
105     private Student getStudentFromConsole() {
106
107         Scanner scanner = new Scanner(System.in);
108
109         Student student = new Student();
110
111         System.out.print("FlowId:");
112         student.setFlowId(scanner.nextInt());
113
114         System.out.print("Type: ");
115         student.setType(scanner.nextInt());
116
117         System.out.print("IdCard:");
118         student.setIdCard(scanner.next());
119
120         System.out.print("ExamCard:");
121         student.setExamCard(scanner.next());
122
123         System.out.print("StudentName:");
124         student.setStudentName(scanner.next());
125
126         System.out.print("Location:");
127         student.setLocation(scanner.next());
128
129         System.out.print("Grade:");
130         student.setGrade(scanner.nextInt());
131
132         return student;
133     }
134
135     public void addNewStudent2(Student student) {
136         String sql = "INSERT INTO examstudent(flowid, type, idcard, "
137                 + "examcard, studentname, location, grade) "
138                 + "VALUES(?,?,?,?,?,?,?)";
139
140         JDBCTools.update(sql, student.getFlowId(), student.getType(),
141                 student.getIdCard(), student.getExamCard(),
142                 student.getStudentName(), student.getLocation(),
143                 student.getGrade());
144     }
145
146     /*
147     public void addNewStudent(Student student) {
148         // 1. 准备一条 SQL 语句:
149         String sql = "INSERT INTO examstudent VALUES(" + student.getFlowId()
150                 + "," + student.getType() + ",‘" + student.getIdCard() + "‘,‘"
151                 + student.getExamCard() + "‘,‘" + student.getStudentName()
152                 + "‘,‘" + student.getLocation() + "‘," + student.getGrade()
153                 + ")";
154
155         System.out.println(sql);
156
157         // 2. 调用 JDBCTools 类的 update(sql) 方法执行插入操作.
158         JDBCTools.update(sql);
159     }
160     */
161
162     //具体查询学生信息的. 返回一个 Student 对象. 若不存在, 则返回 null
163     private Student searchStudent(int searchType) {
164
165         String sql = "SELECT flowid, type, idcard, examcard,"
166                 + "studentname, location, grade " + "FROM examstudent "
167                 + "WHERE ";
168
169         Scanner scanner = new Scanner(System.in);
170
171         // 1. 根据输入的 searchType, 提示用户输入信息:
172         // 1.1 若 searchType 为 1, 提示: 请输入身份证号. 若为 2 提示: 请输入准考证号
173         // 2. 根据 searchType 确定 SQL
174         if (searchType == 1) {
175             System.out.print("请输入准考证号:");
176             String examCard = scanner.next();
177             sql = sql + "examcard = ‘" + examCard + "‘";
178         } else {
179             System.out.print("请输入身份证号:");
180             String examCard = scanner.next();
181             sql = sql + "idcard = ‘" + examCard + "‘";
182         }
183
184         // 3. 执行查询
185         Student student = getStudent(sql);
186
187         // 4. 若存在查询结果, 把查询结果封装为一个 Student 对象
188
189         return student;
190     }
191
192
193     //测试打印查询到的学生信息
194     @Test
195     public void testGetStudent() {
196         // 1. 得到查询的类型
197         int searchType = getSearchTypeFromConsole();
198
199         // 2. 具体查询学生信息
200         Student student = searchStudent(searchType);
201
202         // 3. 打印学生信息
203         printStudent(student);
204     }
205
206
207     @Test
208     public void testAddNewStudent() {
209         Student student = getStudentFromConsole();
210         addNewStudent2(student);
211     }
212
213 }

三、Statement 与 ResultSet
1.通过调用 Connection 对象的 createStatement 方法创建该对象
? Statement st = conn.createStatement();
2.该对象用于执行静态的 SQL 语句,并且返回执行结果
3.Statement 接口中定义了下列方法用于执行 SQL 语句:
? ResultSet excuteQuery(String sql)
? int excuteUpdate(String sql)

通用的INSERT、UPDATA、DELETE方法

 1 //通用的 INSSERT UPDATE DELETE 方法(version 1.0)
 2 public void update(String sql){
 3     //1.获取数据库的连接
 4     Connection conn = null;
 5     Statement st = null;
 6     try{
 7         conn = JDBCUtils.getConnection();
 8         //2.提供一个 Statement 对象,将 sql 传递给数据库中执行
 9         st = conn.createStatement();
10         st.execute(sql);
11     }catch(Exception e){
12         e.printStackTrace();
13     }finally{
14         //3.关闭 Statement 对象及连接
15         JDBCUtils.close(null, st, conn);
16     }
17 }

通用的查询方法,返回一个对象

 1 public <T> T get(String sql, Class<T> clazz) {
 2     Connection conn = null;
 3     Statement st = null;
 4     ResultSet rs = null;
 5     T t = null;
 6     try {
 7         t = clazz.newInstance();
 8         conn = JDBCUtils.getConnection();
 9         st = conn.createStatement();
10         rs = st.executeQuery(sql);
11         /*
12         * 通过 ResultSet 调用 getMetaData()返回一个结果集的元数据:ResultSetMetaData
13         *
14         * 1.getColumnCount():返回结果集的列数
15         * 2.getColumnLabel():返回列的别名
16         */
17         ResultSetMetaData rsmd = rs.getMetaData();
18         int columnCount = rsmd.getColumnCount();
19         if (rs.next()) {
20             for (int i = 0; i < columnCount; i++) {
21                 Object columnVal = rs.getObject(i + 1);// 相应列的值
22                 //String columnName = rsmd.getColumnName(i + 1);
23                 String columnName = rsmd.getColumnLabel(i + 1);
24                 //使用 PropertyUtils 将指定对象 t 的指定属性 columnName 设置为指定的值 columnVal
25                 PropertyUtils.setProperty(t, columnName, columnVal);
26             }
27         }
28     } catch (Exception e) {
29         e.printStackTrace();
30     } finally {
31         JDBCUtils.close(rs, st, conn);
32     }
33     return t;
34 }

//通用的返回多个对象的查询操作

 1 public <T> List<T> getInstances(String sql,Class<T> clazz){
 2     Connection conn = null;
 3     Statement st = null;
 4     ResultSet rs = null;
 5     List<T> list = new ArrayList<T>();
 6     try {
 7         conn = JDBCUtils.getConnection();
 8         st = conn.createStatement();
 9         rs = st.executeQuery(sql);
10         /*
11         * 通过 ResultSet 调用 getMetaData()返回一个结果集的元数据:ResultSetMetaData
12         *
13         * 1.getColumnCount():返回结果集的列数
14         * 2.getColumnLabel():返回列的别名
15         */
16         ResultSetMetaData rsmd = rs.getMetaData();
17         int columnCount = rsmd.getColumnCount();
18         while (rs.next()) {
19             T t = clazz.newInstance();
20             for (int i = 0; i < columnCount; i++) {
21                 Object columnVal = rs.getObject(i + 1);// 相应列的值
22                 //String columnName = rsmd.getColumnName(i + 1);
23                 String columnName = rsmd.getColumnLabel(i + 1);
24                 //使用 PropertyUtils 将指定对象 t 的指定属性 columnName 设置为指定的值 columnVal
25                 PropertyUtils.setProperty(t, columnName, columnVal);
26             }
27             list.add(t);
28         }
29     } catch (Exception e) {
30         e.printStackTrace();
31     } finally {
32         JDBCUtils.close(rs, st, conn);
33     }
34     return list;
35 }

或者采用这个方法(个人比较喜欢)

 1 public List<Map<String, Object>> read(String sql) throws SQLException {
 2         Connection conn = null;
 3         PreparedStatement ps = null;
 4         ResultSet rs = null;
 5         try {
 6             conn = JdbcUtils.getConnection();
 7             ps = conn.prepareStatement(sql);
 8             rs = ps.executeQuery();
 9             ResultSetMetaData rsmd = rs.getMetaData();
10             int count = rsmd.getColumnCount();
11             String[] colNames = new String[count];
12             System.out.println(count);
13             for (int i = 1; i <= count; i++) {
14                 //Object val = rs.getObject(i);
15                 //System.out.println(val);
16                 //System.out.print(rsmd.getColumnClassName(i) + "\t");
17                 //System.out.print(rsmd.getColumnName(i) + "\t");
18                 //System.out.println(rsmd.getColumnLabel(i));
19                 colNames[i - 1] = rsmd.getColumnLabel(i);
20             }
21             List<Map<String, Object>> datas = new ArrayList<Map<String, Object>>();
22
23             while (rs.next()) {
24                 Map<String, Object> data = new HashMap<String, Object>();
25                 for (int i = 0; i < colNames.length; i++) {
26                     data.put(colNames[i], rs.getObject(colNames[i]));
27                 }
28                 datas.add(data);
29             }
30             return datas;
31         } finally {
32             JdbcUtils.free(rs, ps, conn);
33         }
34     }

两种思想:
1.面向接口编程的思想;
2.ORM 思想:ORM:Object Relational Mapping
数据库中的表与 java 中的一个类对应(如: customers 表与 Customer 类对应);数据库中表的一个列与 java 类的一个属性对应(如:表中的 id 列与 Customer类的 id 属性对应);数据库中表的一行(一条数据)与 java 类的一个对象对应

  1 package cn.itcast.jdbc;
  2
  3 import java.lang.reflect.InvocationTargetException;
  4 import java.lang.reflect.Method;
  5 import java.sql.Connection;
  6 import java.sql.PreparedStatement;
  7 import java.sql.ResultSet;
  8 import java.sql.ResultSetMetaData;
  9 import java.sql.SQLException;
 10 import java.util.ArrayList;
 11 import java.util.HashMap;
 12 import java.util.List;
 13 import java.util.Map;
 14
 15 import cn.itcast.jdbc.domain.User;
 16
 17 /**
 18  *
 19  * 2008-12-7
 20  *
 21  * @author <a href="mailto:[email protected]">liyong</a>
 22  *
 23  */
 24 public class ORMTest {
 25
 26     /**
 27      * @param args
 28      * @throws Exception
 29      * @throws InvocationTargetException
 30      * @throws IllegalAccessException
 31      * @throws SQLException
 32      */
 33     public static void main(String[] args) throws SQLException,
 34             IllegalAccessException, InvocationTargetException, Exception {
 35         User user = (User) getObject(
 36                 "select id as Id, name as Name, birthday as Birthday, money as Money  from user where id=1",
 37                 User.class);
 38         System.out.println(user);
 39
 40         Bean b = (Bean) getObject(
 41                 "select id as Id, name as Name, birthday as Birthday, money as Money from user where id=1",
 42                 Bean.class);
 43         System.out.println(b);
 44     }
 45
 46     static List<Object> getObjects(String sql, Class clazz)
 47             throws SQLException, Exception, IllegalAccessException,
 48             InvocationTargetException {
 49         Connection conn = null;
 50         PreparedStatement ps = null;
 51         ResultSet rs = null;
 52         try {
 53             conn = JdbcUtils.getConnection();
 54             ps = conn.prepareStatement(sql);
 55             rs = ps.executeQuery();
 56             String[] colNames = getColNames(rs);
 57
 58             List<Object> objects = new ArrayList<Object>();
 59             Method[] ms = clazz.getMethods();
 60             while (rs.next()) {
 61                 Object object = clazz.newInstance();
 62                 for (int i = 0; i < colNames.length; i++) {
 63                     String colName = colNames[i];
 64                     String methodName = "set" + colName;
 65                     // Object value = rs.getObject(colName);
 66                     // try {
 67                     // Method m = clazz
 68                     // .getMethod(methodName, value.getClass());
 69                     // if (m != null)
 70                     // m.invoke(object, value);
 71                     // } catch (NoSuchMethodException e) {
 72                     // e.printStackTrace();
 73                     // //
 74                     // }
 75                     for (Method m : ms) {
 76                         if (methodName.equals(m.getName())) {
 77                             m.invoke(object, rs.getObject(colName));
 78                             break;
 79                         }
 80                     }
 81                     objects.add(object);
 82                 }
 83             }
 84             return objects;
 85         } finally {
 86             JdbcUtils.free(rs, ps, conn);
 87         }
 88     }
 89
 90     private static String[] getColNames(ResultSet rs) throws SQLException {
 91         ResultSetMetaData rsmd = rs.getMetaData();
 92         int count = rsmd.getColumnCount();
 93         String[] colNames = new String[count];
 94         for (int i = 1; i <= count; i++) {
 95             colNames[i - 1] = rsmd.getColumnLabel(i);
 96         }
 97         return colNames;
 98     }
 99
100     static Object getObject(String sql, Class clazz) throws SQLException,
101             Exception, IllegalAccessException, InvocationTargetException {
102         Connection conn = null;
103         PreparedStatement ps = null;
104         ResultSet rs = null;
105         try {
106             conn = JdbcUtils.getConnection();
107             ps = conn.prepareStatement(sql);
108             rs = ps.executeQuery();
109             String[] colNames = getColNames(rs);
110
111             Object object = null;
112             Method[] ms = clazz.getMethods();
113             if (rs.next()) {
114                 object = clazz.newInstance();
115                 for (int i = 0; i < colNames.length; i++) {
116                     String colName = colNames[i];
117                     String methodName = "set" + colName;
118                     // Object value = rs.getObject(colName);
119                     // try {
120                     // Method m = clazz
121                     // .getMethod(methodName, value.getClass());
122                     // if (m != null)
123                     // m.invoke(object, value);
124                     // } catch (NoSuchMethodException e) {
125                     // e.printStackTrace();
126                     // //
127                     // }
128                     for (Method m : ms) {
129                         if (methodName.equals(m.getName())) {
130                             m.invoke(object, rs.getObject(colName));
131                             break;
132                         }
133                     }
134                 }
135             }
136             return object;
137         } finally {
138             JdbcUtils.free(rs, ps, conn);
139         }
140     }
141 }


两个技术:

1.结果集的元数据: ResultSetMetaData

可用于获取关于 ResultSet 对象中列的类型和属性信息的对象:
  —getColumnName(int column):获取指定列的名称
  —getColumnCount():返回当前 ResultSet 对象中的列数。
  —getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
  —getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。   
  —isNullable(int column):指示指定列中的值是否可以为 null。
  —isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。

 1 public void testResultSetMetaData(){
 2     Connection conn = null;
 3     Statement st = null;
 4     ResultSet rs = null;
 5     String sql = "select order_id id,order_name name,order_date date from `order`";
 6     try{
 7         conn = JDBCUtils.getConnection();
 8         st = conn.createStatement();
 9         rs = st.executeQuery(sql);
10         ResultSetMetaData rsmd = rs.getMetaData();
11         int columnCount = rsmd.getColumnCount();
12         System.out.println(columnCount);
13         while(rs.next()){
14             for(int i = 0;i < columnCount;i++){
15                 System.out.print(rsmd.getColumnName(i + 1) + " ");
16                 System.out.print(rsmd.getColumnLabel(i + 1) + " ");
17                 System.out.println(rs.getObject(i + 1));
18             }
19             System.out.println();
20         }
21     }catch(Exception e){
22         e.printStackTrace();
23     }finally{
24         JDBCUtils.close(rs, st, conn);
25     }
26 }

2.PropertyUtils:使用它的 setProperty(Object obj,String FieldName,Object FieldValue)

1 public void testPropertyUtils() throws Exception{
2     Order order = new Order();
3     System.out.println(order);
4     PropertyUtils.setProperty(order, "id", 1001);
5     PropertyUtils.setProperty(order, "name", "AA");
6     PropertyUtils.setProperty(order, "date", new Date(new java.util.Date().getTime()));
7     System.out.println(order);
8 }

四、PreparedStatement

PreparedStatement 是 Statement 的子接口

a.需要预编译 SQL 语句: PreparedStatement ps = conn.preparedStatement(sql);
b.填充占位符: setObject(int index);//index 从 1 开始
c.execute() / executeUpdate() ; executeQuery(); 返回一个 ResultSet

1.替换原来的 Statement,实现增删改和查的操作
-->Statement 的问题:①拼串 不方便,容易出错 ②存在 sql 注入的问题,可以对数据库进行恶意攻击。

// 实现一个通用的 UPDATE INSERT DELETE 的操作的方法

 1 public void update(String sql, Object... args) {
 2     Connection conn = null;
 3     PreparedStatement ps = null;
 4     try {
 5         // 1.获取连接
 6         conn = JDBCUtils.getConnection();
 7         // 2.返回 PreparedSt 对象,预编译 sql 语句
 8         ps = conn.prepareStatement(sql);
 9         // 3.填充占位符
10         for (int i = 0; i < args.length; i++) {
11             ps.setObject(i + 1, args[i]);
12         }
13         ps.execute();
14     } catch (Exception e) {
15         e.printStackTrace();
16     } finally {
17         JDBCUtils.close(null, ps, conn);
18     }
19 }

// 实现一个通用的查询操作,返回一个对象

 1 public <T> T getInstance(String sql, Class<T> clazz, Object... args) {
 2     Connection conn = null;
 3     PreparedStatement ps = null;
 4     ResultSet rs = null;
 5     try {
 6         // 1.获取连接
 7         conn = JDBCUtils.getConnection();
 8         // 2.预编译 sql 语句,返回 PreparedStatement 对象
 9         ps = conn.prepareStatement(sql);
10         // 3.填充占位符
11         for (int i = 0; i < args.length; i++) {
12             ps.setObject(i + 1, args[i]);
13         }
14         // 4.执行并返回 ResultSet 的对象
15         rs = ps.executeQuery();
16         if (rs.next()) {
17             // 5.创建 T 的对象
18             T t = clazz.newInstance();
19             // 6.将结果集中的列值作为 T 的对象的属性,给予赋值
20             ResultSetMetaData rsmd = rs.getMetaData();
21             int columnCount = rsmd.getColumnCount();
22             for (int i = 0; i < columnCount; i++) {
23                 Object columnVal = rs.getObject(i + 1);
24                 String columnLabel = rsmd.getColumnLabel(i + 1);
25                 PropertyUtils.setProperty(t, columnLabel, columnVal);
26             }
27             return t;
28         }
29     } catch (Exception e) {
30         e.printStackTrace();
31     } finally {
32         // 7.关闭相应的操作
33         JDBCUtils.close(rs, ps, conn);
34     }
35     return null;
36 }

// 实现一个通用的查询操作,返回一个对象的集合

 1 public <T> List<T> getForList(String sql,Class<T> clazz,Object ... args){
 2     Connection conn = null;
 3     PreparedStatement ps = null;
 4     ResultSet rs = null;
 5     List<T> list = new ArrayList<T>();
 6     try{
 7         conn = JDBCUtils.getConnection();
 8         ps = conn.prepareStatement(sql);
 9         for(int i = 0;i < args.length;i++){
10             ps.setObject(i + 1, args[i]);
11         }
12         rs = ps.executeQuery();
13         ResultSetMetaData rsmd = rs.getMetaData();
14         int columnCount = rsmd.getColumnCount();
15         while(rs.next()){
16             T t = clazz.newInstance();
17             for(int i = 0;i < columnCount;i++){
18                 Object columnVal = rs.getObject(i + 1);
19                 String columnLabel = rsmd.getColumnLabel(i + 1);
20                 PropertyUtils.setProperty(t, columnLabel, columnVal);
21             }
22             list.add(t);
23         }
24     }catch(Exception e){
25         e.printStackTrace();
26     }finally{
27         JDBCUtils.close(rs, ps, conn);
28     }
29     return list;
30 }

2.使用 PreparedStatement 的其他优点
-->1.实现大数据类型的数据的插入、修改、查询的操作.
setBlob() getBlob();

// 从数据表中将大数据类型的数据取出

 1 @Test
 2 public void testBlob3(){
 3     Connection conn = null;
 4     PreparedStatement ps = null;
 5     String sql = "select id,name,email,birth,photo from customers where id = ?";
 6     ResultSet rs = null;
 7     InputStream is = null;
 8     FileOutputStream fos = null;
 9     try{
10         conn = JDBCUtils.getConnection();
11         ps = conn.prepareStatement(sql);
12         fos = new FileOutputStream("ym1.jpg");
13         ps.setInt(1, 21);
14         rs = ps.executeQuery();
15         if(rs.next()){
16             int id = rs.getInt("id");
17             String name = rs.getString("name");
18             Date birth = rs.getDate("birth");
19             String email = rs.getString("email");
20             Customer cust = new Customer(id,name,email,birth);
21             System.out.println(cust);
22         }
23         Blob photo = rs.getBlob(5);//获取此 ResultSet 对象的当前行中指定列的值
24         is = photo.getBinaryStream();//获取用于写入此 Blob 对象表示的 BLOB 值的流,输入流
25
26         byte[] b = new byte[1024];
27         int len;
28         while((len = is.read(b)) != -1){
29             fos.write(b, 0, len);//文件输出流,保存大数据文件到ym1.jpg中。
30         }
31     }catch (Exception e) {
32         e.printStackTrace();
33     } finally {
34         JDBCUtils.close(rs, ps, conn);
35         if(fos != null){
36             try {
37                 fos.close();
38             } catch (IOException e) {
39                 // TODO Auto-generated catch block
40                 e.printStackTrace();
41             }
42         }
43         if(is != null){
44             try {
45                 is.close();
46             } catch (IOException e) {
47                 // TODO Auto-generated catch block
48                 e.printStackTrace();
49             }
50         }
51     }
52 }

// 向数据表中修改现有的大数据类型的数据

 1 @Test
 2 public void testBlob2() {
 3     Connection conn = null;
 4     PreparedStatement ps = null;
 5     String sql = "update customers set photo = ? where id = ?";
 6     try {
 7         conn = JDBCUtils.getConnection();
 8         ps = conn.prepareStatement(sql);
 9         ps.setBlob(1, new FileInputStream("ym.jpg"));
10         ps.setInt(2, 21);
11         ps.execute();
12     } catch (Exception e) {
13         e.printStackTrace();
14     } finally {
15         JDBCUtils.close(null, ps, conn);
16     }
17 }

// 向数据库的表中写入大数据类型的数据

 1 @Test
 2 public void testBlob1() {
 3     Connection conn = null;
 4     PreparedStatement ps = null;
 5     String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";
 6     try {
 7         conn = JDBCUtils.getConnection();
 8         ps = conn.prepareStatement(sql);
 9         ps.setString(1, "杨幂 1");
10         ps.setString(2, "[email protected]");
11         ps.setDate(3, new Date(new java.util.Date().getTime()));
12         ps.setBlob(4, new FileInputStream("1.jpg"));
13         ps.execute();
14     } catch (Exception e) {
15         e.printStackTrace();
16     } finally {
17         JDBCUtils.close(null, ps, conn);
18     }
19 }

-->2.使用 PreparedStatement 进行批量操作时,效率优于 Statement.
oracle 是支持批量插入的。
如何实现最优? ①使用 PreparedStatement ②addBatch() executeBatch() clearBatch()
//批量操作,主要指的是批量插入

 1 public void test4() {
 2     Connection conn = null;
 3     PreparedStatement ps = null;
 4     long start = System.currentTimeMillis();
 5     String sql = "insert into dept values(?,?)";
 6     try {
 7         conn = JDBCUtils.getConnection();
 8         ps = conn.prepareStatement(sql);
 9         for (int i = 0; i < 100000; i++) {
10             ps.setInt(1, i + 1);
11             ps.setString(2, "dept_" + (i + 1) + "_name");
12             //1.“攒” SQL
13             ps.addBatch();
14             if( (i + 1) % 250 == 0){
15                 //2.执行 sql
16                 ps.executeBatch();
17                 //3.清空 sql
18                 ps.clearBatch();
19             }
20         }
21     } catch (Exception e) {
22         e.printStackTrace();
23     } finally {
24         JDBCUtils.close(null, ps, conn);
25     }
26     long end = System.currentTimeMillis();
27     System.out.println("花费时间: " + (end - start));//2427
28 }

五、数据库的元数据: DataBaseMetaData(了解)
“元”数据: String name = "AA";
ResutSet :结果集
ResultSetMetaData:结果集的元数据

DatabaseMetaData:数据库的元数据

public class TestDataBaseMetaData {
    public static void main(String[] args) {
        Connection conn = null;
        DatabaseMetaData dbmd = null;
        ResultSet rs = null;
        try{
            conn = JDBCUtils.getConnection();
            //获取数据库的元数据
            dbmd = conn.getMetaData();
            //以字符串的形式返回数据库的名字
            System.out.println(dbmd.getDatabaseProductName());
            //返回数据库的版本号
            System.out.println(dbmd.getDatabaseProductVersion());
            rs = dbmd.getCatalogs();
            //返回含有的各个数据库的名字
            while(rs.next()){
                String databaseName = rs.getString(1);
                System.out.println(databaseName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(rs, null, conn);
        }
    }
}

六、数据库事务(重点)
1.事务:指构成单个逻辑工作单元的操作集合
2.事务处理:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),要么整个事务回滚(rollback)到最初状态
2当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚,为了让多个 SQL 语句作为一个事务执行:
a.调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务
b.在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
c.在出现异常时,调用 rollback(); 方法回滚事务
d.若此时 Connection 没有被关闭, 则需要恢复其自动提交状态

// 以下的两个操作共同构成一个数据库事务。但是在两个操作之间可能出现异常问题。
// 原则上,一旦出现问题,就需要将之前的操作“回滚”!需要对如下的操作进行完善。

1 @Test
2 public void testUpdate() {
3     String sql1 = "update user_table set balance = balance - 100 where user = ?";
4     update(sql1, "AA");
5     System.out.println(10 / 0);
6     String sql2 = "update user_table set balance = balance + 100 where user = ?";
7     update(sql2, "BB");
8 }

3.考虑到数据库事务的话,我们又将原来使用 PreparedStatement 重构的
Statement 的增删改和查的操作,再升级。

// 实现一个通用的 UPDATE INSERT DELETE 的操作的方法(version 3.0)

 1 public void update(Connection conn,String sql, Object... args) {
 2     PreparedStatement ps = null;
 3     try {
 4         ps = conn.prepareStatement(sql);
 5         for (int i = 0; i < args.length; i++) {
 6             ps.setObject(i + 1, args[i]);
 7         }
 8         ps.execute();
 9     } catch (Exception e) {
10         e.printStackTrace();
11     } finally {
12         JDBCUtils.close(null, ps, null);
13     }
14 }

// 实现一个通用的查询操作,返回一个对象(version 3.0)

 1 public <T> T getInstance(Connection conn,String sql, Class<T> clazz, Object... args) {
 2     PreparedStatement ps = null;
 3     ResultSet rs = null;
 4     try {
 5         ps = conn.prepareStatement(sql);
 6         // 填充占位符
 7         for (int i = 0; i < args.length; i++) {
 8             ps.setObject(i + 1, args[i]);
 9         }
10         // 4.执行并返回 ResultSet 的对象
11         rs = ps.executeQuery();
12         if (rs.next()) {
13             // 5.创建 T 的对象
14             T t = clazz.newInstance();
15             // 6.将结果集中的列值作为 T 的对象的属性,给予赋值
16             ResultSetMetaData rsmd = rs.getMetaData();
17             int columnCount = rsmd.getColumnCount();
18             for (int i = 0; i < columnCount; i++) {
19                 Object columnVal = rs.getObject(i + 1);
20                 String columnLabel = rsmd.getColumnLabel(i + 1);
21                 PropertyUtils.setProperty(t, columnLabel, columnVal);
22             }
23             return t;
24         }
25     } catch (Exception e) {
26         e.printStackTrace();
27     } finally {
28         // 7.关闭相应的操作
29         JDBCUtils.close(rs, ps, null);
30     }
31     return null;
32 }

// 实现一个通用的查询操作,返回一个对象的集合(version 3.0)

 1 public <T> List<T> getForList(Connection conn,String sql,Class<T> clazz,Object ...args){
 2     PreparedStatement ps = null;
 3     ResultSet rs = null;
 4     List<T> list = new ArrayList<T>();
 5     try{
 6         ps = conn.prepareStatement(sql);
 7         for(int i = 0;i < args.length;i++){
 8             ps.setObject(i + 1, args[i]);
 9         }
10         rs = ps.executeQuery();
11         ResultSetMetaData rsmd = rs.getMetaData();
12         int columnCount = rsmd.getColumnCount();
13         while(rs.next()){
14             T t = clazz.newInstance();
15             for(int i = 0;i < columnCount;i++){
16                 Object columnVal = rs.getObject(i + 1);
17                 String columnLabel = rsmd.getColumnLabel(i + 1);
18                 PropertyUtils.setProperty(t, columnLabel, columnVal);
19             }
20             list.add(t);
21         }
22     }catch(Exception e){
23         e.printStackTrace();
24     }finally{
25         JDBCUtils.close(rs, ps, null);
26     }
27     return list;
28 }

//考虑到数据库事务,通过 java 程序对数据库中表的操作的模板(掌握)

 1 public void method(){
 2     Connection conn = null;
 3     try{
 4         //1.获取数据库的连接(①conn = JDBCUtils.getConnection(); ②数据库连接池(开发者选择此))
 5         //2.开启事务
 6         conn.setAutoCommit(false);
 7         //3.对数据库中表进行相应的操作(增、删、改、查)(①version 3.0 ②DBUtils 工具类: update() 和 query()方法)
 8         //4.提交事务
 9         conn.commit();
10     }catch(Exception e){
11         e.printStackTrace();
12         try{
13             //5.回滚事务
14             conn.rollback();
15         }catch(Exception e1){
16             e1.printStackTrace();
17         }
18     }finally{
19         //6.关闭数据库的连接(①自己实现数据库相应资源的关闭JDBCUtils.close(null,null,conn); ②使用 DBUtils 工具类的 close()方法)
20     }
21 }

事务的ACID(acid)属性:

1. 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 
2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
3. 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4. 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响

数据库的隔离级别:

1.对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
a.脏读: 对于两个事物 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
b.不可重复读: 对于两个事物 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
c.幻读: 对于两个事物 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
2.数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题.
3.一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱

七、实现 DAO 及其实现类 CustomerDAO 的代码

DAO.java

  1 //DAO: database access object
  2 class ReflectionUtils{
  3     //获取 clazz 对象对应的运行时类的父类的泛型
  4     public static Class getSuperGeneric(Class clazz){
  5         Type type = clazz.getGenericSuperclass();
  6         ParameterizedType p = (ParameterizedType)type;
  7         Type[] ts = p.getActualTypeArguments();
  8         return (Class)ts[0];
  9     }
 10 }
 11
 12 public class DAO<T> {
 13     private Class<T> clazz = null;
 14     //this.getClass()在这个问题中,就是 CustomerDAO
 15     public DAO(){
 16     clazz = ReflectionUtils.getSuperGeneric(this.getClass());
 17     }
 18
 19     //获取数据库的标准的特定含义的值
 20     public <E> E getValue(Connection conn,String sql,Object...args){
 21         PreparedStatement ps = null;
 22         ResultSet rs = null;
 23         try{
 24             ps = conn.prepareStatement(sql);
 25             for(int i = 0;i < args.length;i++){
 26                 ps.setObject(i + 1, args[i]);
 27             }
 28             rs = ps.executeQuery();
 29             if(rs.next()){
 30             return (E)rs.getObject(1);
 31             }
 32         }catch(Exception e){
 33             e.printStackTrace();
 34         }finally{
 35             JDBCUtils.close(rs, ps, null);
 36         }
 37         return null;
 38     }
 39
 40     //返回多个对象,以集合的形式返回
 41     public List<T> getForList(Connection conn,String sql,Object ...args){
 42         PreparedStatement ps = null;
 43         ResultSet rs = null;
 44         List<T> list = new ArrayList<>();
 45         try{
 46             //1.预编译 sql 语句,获取 PreparedStatement 对象
 47             ps = conn.prepareStatement(sql);
 48             //2.填充占位符
 49             for(int i = 0;i < args.length;i++){
 50                 ps.setObject(i + 1, args[i]);
 51             }
 52             //3.返回一个结果集
 53             rs = ps.executeQuery();
 54             ResultSetMetaData rsmd = rs.getMetaData();
 55             int columnCount = rsmd.getColumnCount();
 56             while(rs.next()){
 57                 T t = clazz.newInstance();
 58                 //给 t 对象的相应属性赋值
 59                 for(int i = 0;i < columnCount;i++){
 60                     Object columnVal = rs.getObject(i + 1);
 61                     String columnLabel = rsmd.getColumnLabel(i + 1);
 62                     PropertyUtils.setProperty(t, columnLabel, columnVal);
 63                 }
 64                 list.add(t);
 65             }
 66         }catch(Exception e){
 67             e.printStackTrace();
 68         }finally{
 69             JDBCUtils.close(rs, ps, null);
 70         }
 71         //System.out.println(clazz);
 72         return list;
 73     }
 74
 75     //返回一个对象
 76     public T get(Connection conn,String sql,Object ...args){
 77         PreparedStatement ps = null;
 78         ResultSet rs = null;
 79         try{
 80             //1.预编译 sql 语句,获取 PreparedStatement 对象
 81             ps = conn.prepareStatement(sql);
 82             //2.填充占位符
 83             for(int i = 0;i < args.length;i++){
 84                 ps.setObject(i + 1, args[i]);
 85             }
 86             //3.返回一个结果集
 87             rs = ps.executeQuery();
 88             ResultSetMetaData rsmd = rs.getMetaData();
 89             int columnCount = rsmd.getColumnCount();
 90             if(rs.next()){
 91                 T t = clazz.newInstance();
 92                 //给 t 对象的相应属性赋值
 93                 for(int i = 0;i < columnCount;i++){
 94                     Object columnVal = rs.getObject(i + 1);
 95                     String columnLabel = rsmd.getColumnLabel(i + 1);
 96                     PropertyUtils.setProperty(t, columnLabel, columnVal);
 97                 }
 98                 return t;
 99             }
100         }catch(Exception e){
101             e.printStackTrace();
102         }finally{
103             JDBCUtils.close(rs, ps, null);
104         }
105         //System.out.println(clazz);
106         return null;
107     }
108
109     //通用的增删改的操作
110     public void update(Connection conn,String sql,Object ... args){
111         PreparedStatement ps = null;
112         try{
113             ps = conn.prepareStatement(sql);
114             for(int i = 0;i < args.length;i++){
115                 ps.setObject(i + 1, args[i]);
116             }
117             ps.executeUpdate();
118         }catch(Exception e){
119             e.printStackTrace();
120         }finally{
121             JDBCUtils.close(null, ps, null);
122         }
123     }
124 }

Customer.java

 1 //CustomerDAO 类是用来操作 Customer 类的
 2 public class CustomerDAO extends DAO<Customer>{
 3
 4     // @Test
 5     // public void testGeneric(){
 6         // Class clazz = CustomerDAO.class;
 7         // Type type = clazz.getGenericSuperclass();
 8         // ParameterizedType p = (ParameterizedType)type;
 9         // Type[] ts = p.getActualTypeArguments();
10         // System.out.println(ts[0]);
11     // }
12
13     /**
14     * 获取对应的表中的记录的个数
15     */
16     public long getCount(Connection conn){
17         String sql = "select count(*) from customers";
18         return (long)getValue(conn, sql);
19     }
20
21     /**
22     * 返回 customers 表中的所有数据
23     * @param conn
24     * @return
25     */
26     public List<Customer> getAll(Connection conn){
27         String sql = "select id,name,email,birth from customers";
28         return getForList(conn, sql);
29     }
30
31     /**
32     * 根据指定的 id 返回相应的对象
33     * @param conn
34     * @param customerId
35     */
36     public Customer getInstance(Connection conn,int customerId){
37         String sql = "select id,name,email,birth from customers where id = ?";
38         return get(conn, sql, customerId);
39     }
40
41     /**
42     * 删除指定 customerId 的数据表中的记录
43     * @param conn
44     * @param customerId
45     */
46     public void delete(Connection conn,int customerId){
47         String sql = "delete from customers where id = ?";
48         update(conn, sql, customerId);
49     }
50
51     /**
52     * 向数据表中修改指定 id 的信息为 Customer 对象的信息
53     * @param conn
54     * @param cust
55     */
56     public void update(Connection conn,Customer cust){
57         String sql = "update customers set name = ?,email = ?,birth = ? where id = ?";
58         update(conn, sql,cust.getName(),cust.getEmail(),cust.getBirth(),cust.getId());
59     }
60
61     /**
62     * 向数据表中插入一条数据
63     * @param conn 数据库的连接
64     * @param cust 要插入的 Customer 对象
65     */
66     public void insert(Connection conn,Customer cust){
67         String sql = "insert into customers(name,email,birth)values(?,?,?)";
68         update(conn, sql, cust.getName(),cust.getEmail(),cust.getBirth());
69     }
70 }

TestCustomer.java

 1 public class TestCustomerDAO {
 2     CustomerDAO customerDAO = new CustomerDAO();
 3
 4     @Test
 5     public void testGetCount(){
 6         Connection conn = null;
 7         try{
 8             conn = JDBCUtils.getConnection();
 9             long count = customerDAO.getCount(conn);
10             System.out.println(count);
11         }catch(Exception e){
12             e.printStackTrace();
13         }finally{
14             JDBCUtils.close(null, null, conn);
15         }
16     }
17
18     @Test
19     public void testGetAll(){
20         Connection conn = null;
21         try{
22             conn = JDBCUtils.getConnection();
23             List<Customer> list = customerDAO.getAll(conn);
24             //System.out.println(list);
25             Iterator<Customer> iterator = list.iterator();
26             while(iterator.hasNext()){
27                 System.out.println(iterator.next());
28             }
29         }catch(Exception e){
30             e.printStackTrace();
31         }finally{
32             JDBCUtils.close(null, null, conn);
33         }
34     }
35
36     @Test
37     public void testQuery(){
38         Connection conn = null;
39         try{
40             conn = JDBCUtils.getConnection();
41             Customer cust = customerDAO.getInstance(conn, 13);
42             System.out.println(cust);
43         }catch(Exception e){
44             e.printStackTrace();
45         }finally{
46             JDBCUtils.close(null, null, conn);
47         }
48     }
49
50     @Test
51     public void testDelete(){
52         Connection conn = null;
53         try{
54             conn = JDBCUtils.getConnection();
55             customerDAO.delete(conn, 10);
56         }catch(Exception e){
57             e.printStackTrace();
58         }finally{
59             JDBCUtils.close(null, null, conn);
60         }
61     }
62
63     @Test
64     public void testUpdate(){
65         Connection conn = null;
66         try{
67             conn = JDBCUtils.getConnection();
68             Customer cust = new Customer(10, "张卫健", "[email protected]",new
69             Date(new java.util.Date().getTime()));
70             customerDAO.update(conn, cust);
71         }catch(Exception e){
72             e.printStackTrace();
73         }finally{
74             JDBCUtils.close(null, null, conn);
75         }
76     }
77
78     @Test
79     public void testInsert(){
80         Connection conn = null;
81         try{
82             conn = JDBCUtils.getConnection();
83             Customer cust = new Customer(10, "张卫健", "[email protected]",new
84             Date(new java.util.Date().getTime()));
85             customerDAO.insert(conn, cust);
86         }catch(Exception e){
87             e.printStackTrace();
88         }finally{
89             JDBCUtils.close(null, null, conn);
90         }
91     }
92 }

 八、数据库连接池

C3P0 数据库连接池

 1 // 保证在所有的通过 C3P0 获取的连接中,只有一个 DataSource 的对象。(推荐)
 2 private static DataSource source = null;
 3
 4 static {
 5     source = new ComboPooledDataSource("helloc3p0");
 6 }
 7 // 获取数据库的连接方式 3:使用 c3p0 数据库连接池获取数据库的连接,使用配置文件
 8 public static Connection getConnection3() throws Exception {
 9     return source.getConnection();
10 }

对应的配置文件: c3p0-config.xml

 1 <c3p0-config>
 2 <named-config name="helloc3p0">
 3 <!-- 提供数据库连接的 4 个基本信息 -->
 4 <property name="jdbcUrl">jdbc:mysql:///test</property>
 5 <property name="driverClass">com.mysql.jdbc.Driver</property>
 6 <property name="user">root</property>
 7 <property name="password">123456</property>
 8 <!-- 当连接池中的数量不足时, c3p0 连接一次性向数据库服务器申请的
 9 连接数 -->
10 <property name="acquireIncrement">5</property>
11 <!-- 初始化数据库连接池时,池中存在的连接数 -->
12 <property name="initialPoolSize">10</property>
13 <!-- 数据库连接池中最少容纳的连接数 -->
14 <property name="minPoolSize">5</property>
15 <!-- 数据库连接池中最大容纳的连接数 -->
16 <property name="maxPoolSize">100</property>
17 <!-- 连接池中,最多允许存在的 Statement 的数量 -->
18 <property name="maxStatements">10</property>
19 <!-- 一次连接中,最多容纳的 Statement 的个数 -->
20 <property name="maxStatementsPerConnection">5</property>
21 </named-config>
22 </c3p0-config>

DBCP 数据库连接池

 1 //随着类的加载,使用 BasicDataSourceFactory 的静态方法 createDataSource()返回一个
 2 //DataSource 的对象
 3 private static DataSource source1 = null;
 4 static {
 5     Properties info = new Properties();
 6     // info.load(new FileInputStream("dbcp.properties"));
 7     InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream(
 8     "com/atguigu/java/dbcp.properties");
 9     try {
10         info.load(is);
11         source1 = BasicDataSourceFactory.createDataSource(info);
12     } catch (Exception e) {
13         e.printStackTrace();
14     }
15 }
16 // 获取数据库的连接方式 4:使用 DBCP 数据库连接池获取数据库的连接(推荐)
17 public static Connection getConnection5() throws Exception {
18     return source1.getConnection();
19 }

配置文件 dbcp.properties:

1 username=root
2 password=123456
3 url=jdbc:mysql://127.0.0.1:3306/test
4 driverClassName=com.mysql.jdbc.Driver
5 initialSize=10
6 maxActive=100

九、 DBUtils
提供了 QueryRunner 类,类中有诸多重载 update() 和 query()方法,供使用,用于堆数据库实现操作:增删改查

一些细节问题:

1.设计数据库时候,要考虑编码问题,要主要,创建数据库编码方式和创建表的方式以及java程序运行的编码方式一致,不然会报错,或者导致数据存入到数据库中出现乱码。

2.关于JDBC实现数据库连接时,对日期对象的处理方式:

 1 public class DateTest {
 2
 3     /**
 4      * @param args
 5      * @throws SQLException
 6      */
 7     public static void main(String[] args) throws SQLException {
 8         // create("name2", new Date(), 500.0f);
 9         Date d = read(7);
10         System.out.println(d);
11     }
12
13     static Date read(int id) throws SQLException {
14         Connection conn = null;
15         Statement st = null;
16         ResultSet rs = null;
17         Date birthday = null;
18         try {
19             // 2.建立连接
20             conn = JdbcUtils.getConnection();
21             // conn = JdbcUtilsSing.getInstance().getConnection();
22             // 3.创建语句
23             st = conn.createStatement();
24
25             // 4.执行语句
26             rs = st.executeQuery("select birthday  from user where id=" + id);
27
28             // 5.处理结果
29             while (rs.next()) {
30                 //birthday = new Date(rs.getDate("birthday").getTime());
31                 birthday = rs.getDate("birthday");
32             }
33         } finally {
34             JdbcUtils.free(rs, st, conn);
35         }
36         return birthday;
37     }
38
39     static void create(String name, Date birthday, float money)
40             throws SQLException {
41         Connection conn = null;
42         PreparedStatement ps = null;
43         ResultSet rs = null;
44         try {
45             // 2.建立连接
46             conn = JdbcUtils.getConnection();
47             // conn = JdbcUtilsSing.getInstance().getConnection();
48             // 3.创建语句
49             String sql = "insert into user(name,birthday, money) values (?, ?, ?) ";
50             ps = conn.prepareStatement(sql);
51             ps.setString(1, name);
52             ps.setDate(2, new java.sql.Date(birthday.getTime()));
53             ps.setFloat(3, money);
54
55             // 4.执行语句
56             int i = ps.executeUpdate();
57
58             System.out.println("i=" + i);
59         } finally {
60             JdbcUtils.free(rs, ps, conn);
61         }
62     }
63 }

时间: 2024-11-04 07:38:25

JDBC学习小结的相关文章

JDBC学习笔记一

JDBC JDBC API是一个Java API,可以访问任何类型表列数据,特别是存储在关系数据库中的数据.JDBC代表Java数据库连接. JDBC库中所包含的API任务通常与数据库使用: 连接到数据库 创建SQL或MySQL语句 在数据库中执行SQL或MySQL查询 查看和修改记录 JDBC架构   JDBC API支持两层和三层的处理模式对数据库的访问,但一般JDBC体系结构由两层组成: JDBC API: 这提供了应用程序到JDBC管理器连接. JDBC Driver API: 这支持J

git学习小结

背景:最近因为工作原因,需要将以前的代码库由bitbucket重新布置在一台服务器上,所以就学习了下git,特此记录下 在167这台机器上搭建apache,用做git server,由于以前apache都已经搭好了,所以这里只配置git server 就可以了,此处贴出配置: 服务器搭好了,来到配置中的root目录,git clone https://[email protected]/XXXX 此时,库和服务器都搭好了,用于新库测试的机器也可以从git server上克隆库了,来,我们来试试从

网络编程学习小结

几种网络编程方式: ISAPI.CGI.WinInet.Winsock 它们之间的差别: 1)  ISAPI主要是开发基于浏览器client与server端程序.效率比CGI方式高,并且也扩展了CGI没有的一些功能.(基于TCP/IP模型中的应用层) 2)  CGI主要是开发基于浏览器client与server端程序.(基于TCP/IP模型中的应用层) 3)  WinInet主要是开发client程序.(基于TCP/IP模型中的应用层) 4)  Winsock主要是基于socket来开发clie

MogileFS学习小结

大纲: 一.关于MogileFS 二.常见分布式文件系统 三.MogileFS基本原理 四.MogileFS的实现 一.关于MogileFS 当下我们处在一个互联网飞速发展的信息社会,在海量并发连接的驱动下每天所产生的数据量必然以几何方式增长,随着信息连接方式日益多样化,数据存储的结构也随着发生了变化.在这样的压力下使得人们不得不重新审视大量数据的存储所带来的挑战,例如:数据采集.数据存储.数据搜索.数据共享.数据传输.数据分析.数据可视化等一系列问题. 传统存储在面对海量数据存储表现出的力不从

201671010130 2016-2017-2 《Java程序设计》第四周学习小结

第四周学习小结 本次实验巩固了上次实验分隔数并求和的题,目前这个题有两种做法,一种是不断对数10求余,余数保存在sum中,然后左移一位,直到余数为零.另一种就是将数字强制转换成一个字符串数组String s=String.valueOf(num),根据方法s.toCharArray()将字符分离出来,据"x"-"0"=x,unicode码值相减即可得x的值. 父类和子类能够看两个交集,super关键字是否能够看做一个子类和超类的接口呢? 在子类中可以增加域.增加方法

JDBC学习笔记二

Statement执行更新操作 Statement:Statement 是 Java 执行数据库操作的一个重要方法,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句.Statement对象,用于执行不带参数的简单SQL语句. 通过JDBC向指定的数据表中插入一条记录,需要注意下面的几点: * 1.Statement:用于执行SQL语句的对象 * 1).通过COnnection的createStatement()方法来获取 * 2).通过excuteUpdate(sql)可以执行S

初识ASP.NET---点滴的积累---ASP.NET学习小结

差不多十多天前学习完了北大青鸟的学习视频,没想到没几天的时间就看完了XML视频和牛腩的Javascript视频.学习完了也该总结总结,理理自己的思路,消化一下自己学习到的东西. 视频中的理论知识并不是很多,以例子驱动学起来也不会他过于乏味.全部的学习内容大概的可以用下图表示. 个人感觉这套视频的体系感不是很强,每一集之间老师的串联并不是做得很好,向我等没有教材的有些小的知识无从知晓.但是不能不说这套视频确很适合初学者学习,老师讲解的也不错,从此我也算是入门. 当然要想进一步的了解ASP.NET并

8086汇编学习小结———实时更新

初学IBM-PC 8086,对INT指令不是很理解.现从网上总计如下: 表:DOS系统功能调INT 21H AH 功能 调用参数 返回参数 00 程序终止(同INT 20H) CS=程序段前缀 01 键盘输入并回显 AL=输入字符 02 显示输出 DL=输出字符 03 异步通迅输入 AL=输入数据 04 异步通迅输出 DL=输出数据 05 打印机输出 DL=输出字符 06 直接控制台I/O DL=FF(输入)DL=字符(输出) AL=输入字符 07 键盘输入(无回显) AL=输入字符 08 键盘

《Pro AngularJS》学习小结-01

<Pro AngularJS>该书以一个SportsStore案例为主线铺开. 一.开发环境设置 该书中所用的server开发环境是Deployed,从来没听说过,而且作者也说该server没什么人用,我干脆弃用之.其他的环境包括 NodeJS--这个必须装 karma--测试环境,前期还没有用到,以后认真研究,毕竟AngularJS一大特点是Unit Test bootstrap--这个现在应该普遍使用了,O(∩_∩)O webstorm--现在唯一支持AngularJS插件的IDE 我基本