你的位置:首页 > Java教程

[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   //password11   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. 获取 Connection11     conn = JDBCTools.getConnection();12     System.out.println(conn);13       14     //2. 获取 Statement15     statement = conn.createStatement();16     System.out.println(statement);17       18     //3. 准备 SQL19     String sql = "SELECT id, name, email, birth " +20           "FROM customers";21       22     //4. 执行查询, 得到 ResultSet23     rs = statement.executeQuery(sql);24     System.out.println(rs);25       26     //5. 处理 ResultSet27     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 111 */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 和 Connection44    * @param statement45    * @param conn46   */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    * @return69    * @throws Exception70   */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.Driver2 jdbcUrl=jdbc:mysql://localhost:3306/test3 user=root4 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  : MYSQL10 Target Server Version : 5052411 File Encoding     : 6500112 13 Date: 2015-06-27 15:49:2214 */15 16 SET FOREIGN_KEY_CHECKS=0;17 18 -- ----------------------------19 -- Table structure for examstudent20 -- ----------------------------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=root2 password=1234563 driverClass=com.mysql.jdbc.Driver4 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.properties110     /**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, driverClass119     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 对象. 若不存在, 则返回 null163   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 确定 SQL174     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   @Test195   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   @Test208   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()返回一个结果集的元数据:ResultSetMetaData13     *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 设置为指定的值 columnVal25         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()返回一个结果集的元数据:ResultSetMetaData12     *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 设置为指定的值 columnVal25         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) + "\t");17         //System.out.print(rsmd.getColumnName(i) + "\t");18         //System.out.println(rsmd.getColumnLabel(i));19         colNames[i - 1] = rsmd.getColumnLabel(i);20       }21       List<Map<String, Object>> datas = new ArrayList<Map<String, Object>>();22 23       while (rs.next()) {24         Map<String, Object> data = new HashMap<String, Object>();25         for (int i = 0; i < colNames.length; i++) {26           data.put(colNames[i], rs.getObject(colNames[i]));27         }28         datas.add(data);29       }30       return datas;31     } finally {32       JdbcUtils.free(rs, ps, conn);33     }34   }

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 = clazz121           // .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 block40         e.printStackTrace();41       }42     }43     if(is != null){44       try {45         is.close();46       } catch (IOException e) {47         // TODO Auto-generated catch block48         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.“攒” SQL13       ps.addBatch();14       if( (i + 1) % 250 == 0){15         //2.执行 sql16         ps.executeBatch();17         //3.清空 sql18         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));//242728 }

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 @Test2 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 conn24   * @return25   */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 conn34   * @param customerId35   */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 conn44   * @param customerId45   */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 conn54   * @param cust55   */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   @Test19   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   @Test37   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   @Test51   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   @Test64   public void testUpdate(){65     Connection conn = null;66     try{67       conn = JDBCUtils.getConnection();68       Customer cust = new Customer(10, "张卫健", "zwj@gmail.com",new69       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   @Test79   public void testInsert(){80     Connection conn = null;81     try{82       conn = JDBCUtils.getConnection();83       Customer cust = new Customer(10, "张卫健", "zwj@gmail.com",new84       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.

 

 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=root2 password=1234563 url=jdbc:mysql://127.0.0.1:3306/test4 driverClassName=com.mysql.jdbc.Driver5 initialSize=106 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