zoukankan      html  css  js  c++  java
  • 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 }
    View Code

    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 }
    View Code

    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', 'xyz@atguigu.com', '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     }     
    View Code

    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 }
    View Code

    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 }
    View Code
    1 driver=com.mysql.jdbc.Driver
    2 jdbcUrl=jdbc:mysql://localhost:3306/test
    3 user=root
    4 password=123456
    View Code

    二、实现数据库增删改查

    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;
    View Code

    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
    View Code

    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 }
    View Code

    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 }
    View Code

    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 }
    View Code

    三、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 }
    View Code

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

     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 }
    View Code

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

     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 }
    View Code

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

     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) + "	");
    17                 //System.out.print(rsmd.getColumnName(i) + "	");
    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     }
    View Code

    两种思想:
    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:liyongibm@gmail.com">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 }
    View Code


    两个技术:

    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 }
    View Code

    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 }
    View Code


    四、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 }
    View Code

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

     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 }
    View Code

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

     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 }
    View Code

    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 }
    View Code

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

     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 }
    View Code

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

     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, "yang@126.com");
    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 }
    View Code

    -->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 }
    View Code

    五、数据库的元数据: 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);
            }
        }
    }
    View Code

    六、数据库事务(重点)
    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 }
    View Code

    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 }
    View Code

    // 实现一个通用的查询操作,返回一个对象(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 }
    View Code

    // 实现一个通用的查询操作,返回一个对象的集合(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 }
    View Code

    //考虑到数据库事务,通过 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 }
    View Code

    事务的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 }
    View Code

    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 }
    View Code

    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, "张卫健", "zwj@gmail.com",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, "张卫健", "zwj@gmail.com",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 }
    View Code

     八、数据库连接池

    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 }
    View Code

    对应的配置文件: 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>
    View Code

    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 }
    View Code

    配置文件 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
    View Code

    九、 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 }
    View Code
  • 相关阅读:
    驱动
    设备编号
    makefile 中的赋值
    UART
    c 语言的复杂声明
    linux下arm汇编的常用指令解析
    linux下的arm汇编程序
    ok6410下的uboot分析与实现
    层级选择器的理解
    css外部样式的理解
  • 原文地址:https://www.cnblogs.com/ckysea/p/4603753.html
Copyright © 2011-2022 走看看