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
  • 相关阅读:
    Educational Codeforces Round 20 D. Magazine Ad
    Educational Codeforces Round 20 C. Maximal GCD
    紫书第三章训练2 暴力集
    Educational Codeforces Round 20 B. Distances to Zero
    Educational Codeforces Round 20 A. Maximal Binary Matrix
    紫书第三章训练1 D
    紫书第一章训练1 D -Message Decoding
    HAZU校赛 Problem K: Deadline
    Mutual Training for Wannafly Union #8 D
    紫书第三章训练1 E
  • 原文地址:https://www.cnblogs.com/ckysea/p/4603753.html
Copyright © 2011-2022 走看看