# JDBC

  1. 概念:Java DataBase Connectivity Java 数据库连接, Java 语言操作数据库
  • JDBC 本质:其实是官方(sun 公司)定义的一套操作所有关系型数据库的规则,** 即接口。** 各个数据库厂商去实现这套接口,提供数据库驱动 jar 包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动 jar 包中的实现类。
  1. 快速入门
  • 步骤:

    1. 导入驱动 jar 包 mysql-connector-java-5.1.37-bin.jar
      1. 复制 mysql-connector-java-5.1.37-bin.jar 到项目的 libs 目录下
      2. 右键 -->Add As Library
    2. 注册驱动
    3. 获取数据库连接对象 Connection
    4. 定义 sql
    5. 获取执行 sql 语句的对象 Statement
    6. 执行 sql,接受返回结果
    7. 处理结果
    8. 释放资源

详解各个对象

# DriverManager:驱动管理对象

功能:

  1. 注册驱动:告诉程序该使用哪一个数据库驱动 jar
    static void registerDriver (Driver driver) : 注册与给定的驱动程序 DriverManager 。
    写代码使用: <u>Class.forName("com.mysql.jdbc.Driver");</u>
    通过查看源码发现:在 com.mysql.jdbc.Driver 类中存在静态代码块
    static {
    try {
    java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
    throw new RuntimeException("Can't register driver!");
    }
    }

    注意:mysql5 之后的驱动 jar 包可以省略注册驱动的步骤。

  2. 获取数据库连接:

    • 方法:static Connection getConnection (String url, String user, String password)
    • 参数:
      • url:指定连接的路径
        • 语法:jdbc:mysql://ip 地址 (域名): 端口号 / 数据库名称
        • 例子:jdbc:mysql://localhost:3306/db3
        • 细节:如果连接的是本机 mysql 服务器,并且 mysql 服务默认端口是 3306,则 url 可以简写为:jdbc:mysql:/// 数据库名称
      • user:用户名
      • password:密码

# Connection:数据库连接对象

  1. 功能:
    1. 获取执行 sql 的对象
      • Statement createStatement()
      • PreparedStatement prepareStatement(String sql)
    2. 管理事务:
      • 开启事务:setAutoCommit (boolean autoCommit) :调用该方法设置参数为 false,即开启事务
      • 提交事务:commit ()
      • 回滚事务:rollback ()

# Statement:执行 sql 的对象

  1. 执行 sql

    1. boolean execute (String sql) :可以执行任意的 sql -- 了解
    2. int executeUpdate (String sql) :执行 DML(insert、update、delete)语句、DDL (create,alter、drop) 语句
      • 返回值:影响的行数,可以通过这个影响的行数判断 DML 语句是否执行成功 返回值 > 0 的则执行成功,反之,则失败。
    3. ResultSet executeQuery (String sql) :执行 DQL(select) 语句
  2. 练习:

    1. account 表 添加一条记录
    2. account 表 修改记录
    3. account 表 删除一条记录
     代码:
    	Statement stmt = null;
         Connection conn = null;
         try {
             //1. 注册驱动
             Class.forName("com.mysql.jdbc.Driver");
             //2. 定义sql
             String sql = "insert into account values(null,'王五',3000)";
             //3.获取Connection对象
             conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
             //4.获取执行sql的对象 Statement
             stmt = conn.createStatement();
             //5.执行sql
             int count = stmt.executeUpdate(sql);//影响的行数
             //6.处理结果
             System.out.println(count);
             if(count > 0){
                 System.out.println("添加成功!");
             }else{
                 System.out.println("添加失败!");
             }
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (SQLException e) {
             e.printStackTrace();
         }finally {
             //stmt.close();
             //7. 释放资源
             //避免空指针异常
             if(stmt != null){
                 try {
                     stmt.close();
                 } catch (SQLException e) {
                     e.printStackTrace();
                 }
             }
    
             if(conn != null){
                 try {
                     conn.close();
                 } catch (SQLException e) {
                     e.printStackTrace();
                 }
             }
         }
    

# ResultSet:结果集对象,封装查询结果

  • boolean next (): 游标向下移动一行,判断当前行是否是最后一行末尾 (是否有数据),如果是,则返回 false,如果不是则返回 true

  • getXxx (参数): 获取数据

    • Xxx:代表数据类型 如: int getInt () , String getString ()
    • 参数:
      1. int:代表列的编号,从 1 开始 如: getString (1)
      2. String:代表列名称。 如: getDouble ("balance")
  • 注意:

    • 使用步骤:

      1. 游标向下移动一行
      2. 判断是否有数据
      3. 获取数据

      // 循环判断游标是否是最后一行末尾。

      while(rs.next()){
               // 获取数据
               //6.2 获取数据
               int id = rs.getInt(1);
               String name = rs.getString("name");
               double balance = rs.getDouble(3);
      		System.out.println(id + "---" + name + "---" + balance);
       }

练习:jdbcDemo7
* 定义一个方法,查询 emp 表的数据将其封装为对象,然后装载集合,返回。

1.定义Emp类
2. 定义方法 public List<Emp> findAll(){}
3. 实现方法 select * from emp;

# PreparedStatement:执行 sql 的对象

  1. SQL 注入问题:在拼接 sql 时,有一些 sql 的特殊关键字参与字符串的拼接。会造成安全性问题

  2. 输入用户随便,输入密码:a' or 'a' = 'a

  3. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'

  4. 解决 sql 注入问题:使用 PreparedStatement 对象来解决

  5. 预编译的 SQL:参数使用?作为占位符

  6. 步骤: // 重点

    1. 导入驱动 jar 包 mysql-connector-java-5.1.37-bin.jar
    2. 注册驱动
    3. 获取数据库连接对象 Connection
    4. 定义 sql
      • 注意:sql 的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
    5. 获取执行 sql 语句的对象 PreparedStatement Connection.prepareStatement (String sql)
    6. 给?赋值:
      • 方法: setXxx (参数 1, 参数 2)
        • 参数 1:?的位置编号 从 1 开始
        • 参数 2:?的值
    7. 执行 sql,接受返回结果,不需要传递 sql 语句
    8. 处理结果
    9. 释放资源
  7. 注意:后期都会使用 PreparedStatement 来完成增删改查的所有操作

  8. 可以防止 SQL 注入

  9. 效率更高

# 抽取 JDBC 工具类 : JDBCUtils

目的:简化书写 jdbcUtils + jdbcDemo7 + jdbc.properties 实现练习

分析:1 注册驱动也抽取,2 抽取一个方法获取连接对象

需求:不想传递参数(麻烦),还得保证工具类的通用性。

解决:配置文件 jdbc.properties

url=
	user=
	password=
	driver=

# JDBC 控制事务

事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

操作:1 开启事务 2 提交事务 3 回滚事务

使用 Connection 对象来管理事务

  • 开启事务:setAutoCommit (boolean autoCommit) :调用该方法设置参数为 false,即开启事务
    • 在执行 sql 之前开启事务
  • 提交事务:commit ()
    • 当所有 sql 都执行完提交事务
  • 回滚事务:rollback ()
    • 在 catch 中回滚事务
public class JDBCDemo10 {
	    public static void main(String[] args) {
	        Connection conn = null;
	        PreparedStatement pstmt1 = null;
	        PreparedStatement pstmt2 = null;
	
	        try {
	            //1. 获取连接
	            conn = JDBCUtils.getConnection();
	            // 开启事务
	            conn.setAutoCommit(false);
	
	            //2. 定义 sql
	            //2.1 张三 - 500
	            String sql1 = "update account set balance = balance - ? where id = ?";
	            //2.2 李四 + 500
	            String sql2 = "update account set balance = balance + ? where id = ?";
	            //3. 获取执行 sql 对象
	            pstmt1 = conn.prepareStatement(sql1);
	            pstmt2 = conn.prepareStatement(sql2);
	            //4. 设置参数
	            pstmt1.setDouble(1,500);
	            pstmt1.setInt(2,1);
	
	            pstmt2.setDouble(1,500);
	            pstmt2.setInt(2,2);
	            //5. 执行 sql
	            pstmt1.executeUpdate();
	            // 手动制造异常
	            int i = 3/0;
	
	            pstmt2.executeUpdate();
	            // 提交事务
	            conn.commit();
	        } catch (Exception e) {
	            // 事务回滚
	            try {
	                if(conn != null) {
	                    conn.rollback();
	                }
	            } catch (SQLException e1) {
	                e1.printStackTrace();
	            }
	            e.printStackTrace();
	        }finally {
	            JDBCUtils.close(pstmt1,conn);
	            JDBCUtils.close(pstmt2,null);
	        }
	   }

# 数据库连接池

  1. 概念:其实就是一个容器 (集合),存放数据库连接的容器。
    当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

  2. 好处: 节约资源 用户访问高效

  3. 实现:

    1. 标准接口:DataSource Javax.sql 包下的
      1. 方法:
        • 获取连接:getConnection ()
        • 归还连接:Connectionless ()。如果连接对象 Connection 是从连接池中获取的,那么调用 Connection.close () 方法,则不会再关闭连接了。而是归还连接
    2. 一般我们不去实现它,有数据库厂商来实现
      1. C3p0:数据库连接池技术
      2. Druid:数据库连接池实现技术,由阿里巴巴提供

# C3p0:数据库连接池技术

步骤:

  1. 导入 jar 包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar

    不要忘记导入数据库驱动 jar 包

  2. 定义配置文件:

    名称: c3p0.properties 或者 c3p0-config.xml

    ​ 路径:直接将文件放在 src 目录下即可。

  3. 创建核心对象 数据库连接池对象 ComboPooledDataSource

  4. 获取连接: getConnection

代码:

  1. 创建数据库连接池对象

    DataSource ds = new ComboPooledDataSource();

  2. 获取连接对象
    Connection conn = ds.getConnection ();

# Druid:数据库连接池

# 步骤

1 导入 jar 包 druid-1.0.9.jar

2 定义配置文件:

  • 是 properties 形式的
  • 可以叫任意名称,可以放在任意目录下

3 加载配置文件。Properties

4 获取数据库连接池对象:通过工厂类来获取 DruidDataSourceFactory

5 获取连接:getConnection

1 导入jar包
2 导入配置文件
3 加载配置文件
  	Properties pro = new Properties();
 	 InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
 	 pro.load(is);
4  获取连接池对象
 	 DataSource ds = DruidDataSourceFactory.createDataSource(pro);
5  获取连接
	  Connection conn = ds.getConnection();

# 定义工具类

  1. 定义一个类 JDBCUtils
  2. 提供静态代码块加载配置文件,初始化连接池对象
  3. 提供方法
    1. 获取连接方法:通过数据库连接池获取连接
    2. 释放资源
    3. 获取连接池的方法

# Spring JDBC

  • Spring 框架对 JDBC 的简单封装。提供了一个 JDBCTemplate 对象简化 JDBC 的开发

  • 步骤:

  1. 导入 jar 包

  2. 创建 JdbcTemplate 对象。依赖于数据源 DataSource
    JdbcTemplate template = new JdbcTemplate(ds);
    3. 调用 JdbcTemplate 的方法来完成 CRUD 的操作
    update (): 执行 DML 语句。增、删、改语句
    4.queryForMap (): 查询结果将结果集封装为 map 集合,将列名作为 key,将值作为 value 将这条记录封装为一个 map 集合
    注意:这个方法查询的结果集长度只能是 1

  3. queryForList (): 查询结果将结果集封装为 list 集合
    注意:将每一条记录封装为一个 Map 集合,再将 Map 集合装载到 List 集合中

  4. query (): 查询结果,将结果封装为 JavaBean 对象
    uery 的参数:RowMapper
    一般我们使用 BeanPropertyRowMapper 实现类。可以完成数据到 JavaBean 的自动封装
    new BeanPropertyRowMapper <类型>(类型.class)

  5. queryForObject:查询结果,将结果封装为对象

  6. 般用于聚合函数的查询

public void test6_2(){
	String sql = "select * from emp";
	List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
	for (Emp emp : list) {
		System.out.println(emp);
	}
}