一、JDBCAPI

1、JDBC的概念​

Java DataBase Connectivity​ JDBC是官方(sun公司)定义的一套操作所有关系型数据库的接口,厂商实现这套接口(数据库驱动jar包)。

2、API
1、注册驱动
2、获取数据库连接对象 Connection
3、定义sql
4、获取执行sql语句的对象 Statement,Pre(防止sql注入,预处理对象)
5、执行sql,接受返回结果
6、处理结果(封装到对象中等)
7、释放资源
// 底层API使用规范。学会封装 | 使用工具
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");

// 获取连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql:127.0.0.1:3306/db_temp", "root", "root");
// 定义sql语句
String sql = "update account set xx = xx where id = 1";

// 获取执行sql的对象
StatementStatement stmt = conn.createStatement(); 
// 执行sql,操作影响行数
int count = stmt.executeUpdate(sql);  
// 处理判断
assert count > 0;
// finally,release,must
stmt.close();
conn.close();
3、释放资源
Statement stmt = null;
Connection conn = null;
try {    
    // 处理结果    
    assert count > 0;    
    System.out.println(count);
} catch (ClassNotFoundException e) {    
    e.printStackTrace();
} catch (SQLException e) {    
    e.printStackTrace();
}finally {    
    // stmt.close();    
    // 释放资源    
    // 避免空指针异常    
    if(stmt != null){        
        try {            
            stmt.close();        
        } catch (SQLException e) {            
            e.printStackTrace();        
        }    
    }    
    if(conn != null){        
	try {            
	    conn.close();        
	} catch (SQLException e) {            
	    e.printStackTrace();        
	}    
    }
}
4、API说明
4.1、连接和执行对象
// DriverManager:获取数据库连接对象
// Connection:数据库连接对象,获取执行sql语句的对象,事物管理
//-------------事物控制--------------
conn.setAutoCommit(boolean autoCommit)
//关闭自动事务管理
conn.commit()
conn.rollback()
//------------sql执行对象
Statement createStatement();
PreparedStatement prepareStatement(String sql);  
// 解决sql注入
// 执行sql的方法
boolean execute(String sql);  
// 可以执行任意的sql 了解
// 增删改操作
int executeUpdate(String sql);  
// 执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
// 查操作
ResultSet executeQuery(String sql);  // 执行DQL(select)语句
4.2、获取查询结果集
// 执行sql语句,返回结果集ResultSet  
// 结果集的封装
boolean next();

// 结果集遍历的方法
while(rs.next()){  
    // 有下一行数据:返回true    
    int id = rs.getInt(1);  // 括号:index
    String name = rs.getString("name");  // 括号:fieldName
    double balance = rs.getDouble(3);    
    System.out.println(id + "---" + name + "---" + balance);
}
5、解决sql注入问题​

利用sql中的一些语法规则、特殊符号–让服务器跳过(忽略)对某一部分数据的校验。

select * from user where name = +' + 变量 + ' + and password = +'+ 变量 +';
变量 = xx'or 1 = 1  --select * from user where name = 'xx' or 1 = 1  --' + and password = +'+ 变量 +';
//----------解决方式--------------
// 使用PreparedStatement对象来解决 
// 预编译的SQL:参数使用?作为占位符
// 见事务控制部分
6、结果封装

查询操作,得到到一行一行的结果集。

// 定义User类:实体类(类名、属性名和数据库名、字段名对应)
// public List<User> findAll(){} 
// 实体类对象userObj 
// 查询数据集合,ResultSet
 // 字段遍历,赋值给实体类对象
 userObj.setName(re.getString("name"))
 // 实现方法 
 select * from user;
List<User> list = new List<User>; 
 // 全局·集合
while (rs.next()) {
   User obj = new User();
   // 实体类对象        
   // 获取数据   
   int id = rs.getInt(1);  // index
   String name = rs.getString("name");  // or fieldName   
   double balance = rs.getDouble(3);
   // 封装数据    
   obj.setId(id);
   obj.setName(name);
   obj.setBalance(balance);
   System.out.println(obj);
   // toString方法        
   // 对象放到集合中    
   list.append(obj);
}
 // 循环结束,数据封装完成
 // 遍历集合:增强for

二、冗余封装

1、封装工具类​ 将数据库信息封装到一个配置文件中,通过类加载器进行解析,完成数据库配置,对外提供一个返回数据库连接的方法。
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils {
  private static String url;
  private static String user;
  private static String password;
  private static String driver;
  
  // 静态代码块:类初始化仅仅加载一次。(静态变量、父类非静态、父类静态代码块、父类构造、子···)
  static {
      try {
          ClassLoader classLoader = JDBCUtils.class.getClassLoader();  // 类加载器获取配置文件

          // properties文件  Java文件式式数据结构            
          URL res = classLoader.getResource("jdbc.properties");

          assert res != null;
          String path = res.getPath();
          System.out.println(path);

          // Properties集合类            
          Properties pro = new Properties();
          pro.load(new FileReader(path));
          // 获取数据,赋值

          url = pro.getProperty("url");
          user = pro.getProperty("user");
          password = pro.getProperty("password");
          driver = pro.getProperty("driver");

          // 注册驱动            
          Class.forName(driver);
      } catch (IOException | ClassNotFoundException e) {
          e.printStackTrace();
      }
  }

  // 对外提供一个方法,调用方法返回数据库连接conn    
  public static Connection getConnection() throws SQLException {
      return DriverManager.getConnection(url, user, password);  // 返回:conn    
  }

  public static void close(ResultSet rs, Statement stmt, Connection conn) {
      // 资源释放,可能没有Result,但是Statement、Connection都有,可以使用方法重载(参数不同)    
  }
}


Connection conn = JDBCUtils.getConnection();
2、释放资源(完善)​

调用工具类中的释放资源的方法(释放结果对象、sql执行对象、数据库连接对象)

// 调用使用方式
JDBCUtils.close(null,stmt,conn);
// DML(增删改)操作,没有查询结果集
JDBCUtils.close(rs,stmt,conn);

public class JDBCUtils {
  public static void close(ResultSet rs, Statement stmt, Connection conn) {
      if (rs != null) {
          try {
              rs.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      if (stmt != null) {
          try {
              stmt.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      if (conn != null) {
          try {
              conn.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
  }
}

三、事物控制

一般的都是基于同一个conn,如果涉及到多个服务(多个数据库):查看分布式事务管理。复习MySQL事务部分。

1、说明
// 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
// 使用Connection对象来管理事务
// 开启事务:
setAutoCommit(false);  // 手动  
// sql语句 
// 提交事务:    
commit(); 
    // 回滚事务: 
    rollback();  // 在catch中回滚事务
2、小案例(防止sql注入)
class JDBCDemo {
  public static void main(String[] args) throws SQLException {
      Connection conn = null;
      PreparedStatement pstmt1 = null;
      PreparedStatement pstmt2 = null;
      try {
          // 1.获取连接 
          conn = JDBCUtils.getConnection();
          //开启事务            
          conn.setAutoCommit(false);
          String sql1 = "update account set balance = balance - ? where id = ?";
          String sql2 = "update account set balance = balance + ? where id = ?";
          pstmt1 = conn.prepareStatement(sql1);
          pstmt2 = conn.prepareStatement(sql2);
          pstmt1.setDouble(1, 500);
          pstmt1.setInt(2, 1);
          pstmt2.setDouble(1, 500);
          pstmt2.setInt(2, 2);
          pstmt1.executeUpdate();
          // 手动制造异常            
          int i = 1 / 0;
          pstmt2.executeUpdate();
          // 提交事务            
          conn.commit();
      } catch (Exception e) {
          // 事务回滚            
          try {
              if (conn != null) {
                  conn.rollback();
              }
          } catch (SQLException e1) {
              e1.printStackTrace();
          }
          e.printStackTrace();
      } finally {
          JDBCUtils.close(null, pstmt1, conn);
      }
  }
}

四、数据库连接池​

高效执行

1、连接池接口
// 数据库厂商实现该接口
public interface DataSource {
  // 取出连接对象,厂商实现 
  getConnection();
  // 归还对象直接调用 close();
}
2、C3P0数据库连接池

注意C3P0版本和MySQL版本,以及JDBC-url配置

   // 第三方:导入2个jar包
   // 定义配置文件(名字固定放到src下)
   // 创建核心对象
   // 获取连接getConnection();
2.1、实现配置
<!--文件名字:c3p0-config.xml-->
<c3p0-config>
 <!-- 使用默认的配置读取连接池对象 -->
 <default-config>
     <!--  连接参数 -->
     <property name="driverClass">com.mysql.jdbc.Driver</property>
     <property name="jdbcUrl">jdbc:mysql://localhost:3306/db_temp?&amp;useSSL=false&amp;serverTimezone=UTC</property>
     <property name="user">root</property>
     <property name="password">root</property>

     <!-- 连接池参数 -->
     <!--初始化申请的连接数量-->
     <property name="initialPoolSize">5</property>

     <!--最大的连接数量-->
     <property name="maxPoolSize">10</property>

     <!--超时时间-->
     <property name="checkoutTimeout">3000</property>

 </default-config>

 <named-config name="otherc3p0">
     <!--  连接参数 -->
     <property name="driverClass">com.mysql.jdbc.Driver</property>
     <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3?&amp;useSSL=false&amp;serverTimezone=UTC</property>
     <property name="user">root</property>
     <property name="password">root</property>
     <!-- 连接池参数 -->
     <property name="initialPoolSize">5</property>
     <property name="maxPoolSize">8</property>
     <property name="checkoutTimeout">1000</property>
 </named-config>
</c3p0-config>
2.2、实现代码
public class C3P0Demo2 {    public static void main(String[] args) throws SQLException {        // 获取DataSource,使用默认配置        DataSource ds  = new ComboPooledDataSource();              for (int i = 1; i <= 11 ; i++) {        // 获取连接            Connection conn = ds.getConnection();            System.out.println(i+":"+conn);            if(i == 5){                // 归还连接到连接池中                conn.close();            }        }    }
3、Druid数据库连接池
// 导入jar包
// 配置文件:Properties,名字任意,路径任意,手动加载
// 获取数据库连接池对象:工厂
// 获取连接
getConnection();
3.1、配置文件
driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://192.168.3.3:33306/Demo1username=rootpassword=121388
// 初始化连接数量
initialSize=5
// 最大连接数
maxActive=10
// 最大等待时间
maxWait=3000

`##### 3.2、maven坐标

<!--版本搜索一波--><dependency>    <groupId>com.alibaba</groupId>    <artifactId>druid</artifactId>    <version></version></dependency>
3.3、代码
public class DruidDemo {    public static void main(String[] args) throws Exception {        //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();        System.out.println(conn);    }}

五、JdbcTemapate

学会使用工具

1、针对连接池设计出来的
/** 参数:一个数据库连接池对象DataSource
* 返回值:数据库连接对象Connection
* 方法封装:基础的CRUD,有JdbcTUserlate对象调用
* 方法参数:sql语句,sql参数,封装结果集的RowMapper对象(自定义)
* 优化:自动释放资源(close)
*/
2、代码
class JdbcTemplateDemo {
    public static void main(String[] args) {
        // 带入jar包
        // 创建JdbcTUserlate对象, 把连接池传过来
        JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
        // 生成sql
        String sql = "select * from fruit";
        // 执行方法
        Object list = (Object) jdbctUserlate.queryForList(sql);
        // 自动释放资源,自动归还连接到连接池
        System.out.println(list);
    }
}
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐