Java_10_JDBC

JDBC连接数据库

概述:JDBC(Java Data Base Connectivity),Java数据库连接。Java程序通过JDBC可以操作数据库,实现数据持久化。
JDBC API:官方Sun公司定义的一套操作所有关系型数据库的规则(接口),规范了应用程序和数据库的链接,执行sql语句,并得到返回结果等各种操作,相关的接口和类在java.sqljavax.sql

JDBC使用流程

步骤:

  1. 注册驱动 -> DriverManager加载Driver类。
  2. 获取数据库连接 -> 获取Connection连接。
  3. 获取执行SQL语句对象 -> 获取Statement对象。
  4. 执行SQL语句并处理返回 -> ResultSet集合存储返回结果集,或返回影响条数。
  5. 处理结果
  6. 释放资源

连接数据库方式

// 方法一:通过new获取Driver驱动对象,并手动连接数据库
Driver driver = new com.mysql.jdbc.Driver();
String sqlUrl = "jdbc:mysql://localhost:3306/db1";
//创建Properties对象存储用户信息,并获取数据连接
Properties sqluser = new Properties();
sqluser.setProperty("user","root");
sqluser.setProperty("password","123456");
Connection sqlconnect = driver.connect(sqlUrl, sqluser);
// String user = "root";
// String password = "123456";
// Connection sqlconnection = DriverManager.getConnection(sqlUrl, user, password);

// 接数据库
String sql = "insert into student values(8101,'张三',18,101)";
Statement sqlstatement = sqlconnect.createStatement();
int rows = sqlstatement.executeUpdate(sql);
// 执DML操作,返回影响行数
System.out.println(rows>0?"成功":"失败");
sqlstatement.close();
sqlconnect.close();
// 方式二:通过反射加载Driver类并获取对象,动态加载,减少依赖,更为灵活
// 通过反射机制获取Driver对象实例
Class<?> drivercla = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) drivercla.newInstance();
String sqlUrl = "jdbc:mysql://localhost:3306/db1";
Properties sqluser = new Properties();
sqluser.setProperty("user","*****");
sqluser.setProperty("password","****");
Connection sqlconnect = driver.connect(sqlUrl, sqluser);
sqlconnect.close();
// 方式三:
// 加载Driver类时,底层(静态代码块)自动调用DriverManager.registerDriver()完成驱动注册
Class.forName("com.mysql.jdbc.Driver");
// mysql驱动5.1.6以后使用jdbc4,无需显式调用Class.forname()注册驱动而是自动调用驱动
// 驱动jar包下META-INF\services\java.sql.Driver文本中的类名称去注册
String sqlUrl = "jdbc:mysql://localhost:3306/db1";
String user = "****";
String password = "****";
//可以用properties配置文件保存以上信息
Connection sqlconnection = DriverManager.getConnection(sqlUrl, user, password);
String sql = "insert into student values(8101,'张三',18,101)";
Statement sqlstatement = sqlconnection.createStatement();
int rows = sqlstatement.executeUpdate(sql);
System.out.println(rows>0?"成功":"失败");
sqlstatement.close();
sqlconnection.close();

JDBC API概述

在这里插入图片描述

Statement接口:

  1. 用于执行静态SQL语句并返回其生成的结果的对象
  2. 建立连接之后,需要对数据库进行访问,可以通过:
    • Statement,存在SQL注入风险
    • PreparedStatement,预处理,减少编译次数,解决SQL注入
    • CallableStatement
//SQL注入举例
String sql = 
    "select * from users where id =  '1' or ' and password = 'or '1' = '1'";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
    System.out.println("登录成功");
}

//PreparedStatement举例
String sql = "select * from users where id = ? and password = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"123");
preparedStatement.setString(2,"123456");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
    System.out.println("登录成功");
}
resultSet.close();
preparedStatement.close();
connection.close();

ResultSet结果集:

  1. 表示数据库结果集的数据表,通常由执行数据库查询的语句生成
  2. ResultSet对象保持一个指针只想其当前的数据行,最初光标位于第一行之前
  3. next方法将指针移动到下一行,并且由于ResultSet对象中没有下一行时返回false,故可用while循环来遍历结果集
  4. Result是一个接口,具体实现由JDBC实现
//定语mysql查询语句
String sql = "select * from new";
//执行sql语句返回ResultSet结果集
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
    int id = resultSet.getInt(1);
    String connent = resultSet.getString(2);
    System.out.println(id+"---"+connent);
}
resultSet.close();

封装简易JDBCUtils

//获取连接和关闭资源在数据库连接中反复使用,为了避免代码赘余,可以定义一个工具类进行连接数据库与关闭资源
public class JdbcUtils {
    private static String user;
    private static String password;
    private static String url;
    private static String driver;
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src/com/lxl/mysql.properties"));
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driver = properties.getProperty("driver");
            Class.forName(properties.getProperty("driver"));
        } catch (Exception e) {
            throw new RuntimeException(e);
            //实际开发中多将编译异常转为运行异常,由调用者自行处理
        }
    }
    //获取连接
    public static Connection getConnection() {
        try {//连接数据库,返回Connection对象
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    //关闭资源
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

JDBC实现事务

基本介绍:

  1. JDBC中当一个Connection对象创建时,默认情况下自动提交事务,每次执行sql语句成功就会自动提交,无法回滚
  2. JDBC使用事务使多个sql语句作为一个整体执行
  3. 调用Connection对象的setAutoCommit(false)取消自动提交事务,可以视为开启一个不会自动提交的事务
  4. 当整体的sql语句执行成功后,调用commit()提交事务
  5. 当某个sql语句执行失败之后,调用rollback()回滚事务
Connection connection = null;
PreparedStatement statement = null;
String sql1 = "update account set money = money - 100 where `name` = ?";
String sql2 = "update account set money = money + 100 where `name` = ?";
Savepoint savepoint1 = null;
try {
    connection = JdbcUtils.getConnection();
    connection.setAutoCommit(false);
    //取消事务自动提交,相当于开启事务
    statement = connection.prepareStatement(sql1);
    statement.setString(1,"tom");
    //执行第一条sql语句
    statement.executeUpdate();
    //savepoin t1 = connection.setSavepoint("firsetsql");
    //设置保存点,返回Savepoint对象
    //int i = 1/0;//设置一个算数异常
    statement = connection.prepareStatement(sql2);
    statement.setString(1,"jack");
    //执行第二条sql语句
    statement.executeUpdate();
    connection.commit();//所有sql语句执行成功,提交事务
} catch (Exception e) {
    try {
        //connection.rollback(t1)//回滚到保存点t1
        connection.rollback();//事务回滚
        System.out.println("事件发生回滚");
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
    e.printStackTrace();
} finally {
    try {
        JdbcUtils.close(null,statement,connection);
        //调用工具类close()关闭资源
    } catch (Exception e) {
        e.printStackTrace();
    }
}

JDBC批处理

基本介绍:

  1. 当需要成批插入或更新记录时,可以采取批量更新机制,该机制允许多条sql语句一次性提交给数据库批量处理,通常情况下比单独提交更具效率

  2. JDBC批处理机制包括如下方法(Statement对象调用):

    • addBatch()添加需批处理的sql语句
    • executeBatch()执行批处理语句
    • clearBatch()清空批处理语句
  3. JDBC连接数据库时使用批处理功能,需在url中添加参数:

?rewriteBatchedStatements=true

  1. 批处理通常与PreparedStatement一起使用,即可减少编译次数,又减少运行参数,大幅提高效率
Connection connection = null;
PreparedStatement statement = null;
String sql1 = "insert into account values(?,?)";
try {
    connection = JdbcUtils.getConnection();
    statement = connection.prepareStatement(sql1);
    for (int i = 1; i < 5001; i++) {
        statement.setInt(1,i);
        statement.setString(2,"name"+i);
        statement.addBatch();//将sql语句加入预处理包
        if (i % 1000 == 0) {
            statement.executeBatch();//每1000条记录执行一次批处理语句
        }
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {
    try {
        JdbcUtils.close(null,statement,connection);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

数据库连接池

概述:传统JDBC数据库连接弊端:每次都是用DriverManager获取,每次与数据库建立连接都需要将Connection加载到内存中,在验证IP地址、用户、密码。过于频繁的连接数据库会占用大量系统资源,从而造成服务器崩溃。每次使用数据库连接后若程序异常而未关闭连接、或多过连接都将导致数据库内存泄露、MySQL崩溃,导致需重启数据库。

数据库连接池基本概念:

  1. 预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从缓冲池中取出一个,使用完毕后返回缓冲池。
  2. 数据库连接池负责分配、管理、释放数据库连接,它允许应用程序反复使用一个现有的数据库连接,而不是重新建立。
  3. 当程序向连接池请求的连接数量大于最大连接数量时,未分配连接的请求就会被加入等待队列中。

数据库连接池使用javax.sql.DataSource来表示,该接口由第三方提供实现:

  1. C3P0,速度较慢,稳定性好(hrbernate、spring)底层使用C3P0
  2. DBCP,速度较快,稳定性差
  3. Proxool,可监控连接池状态,稳定性中
  4. BoneCP速度快
  5. Druid(德鲁伊),阿里提供,集DBCP、C3P0、Proxool优点的连接池

C3P0连接池

//使用配置文件配置连接池
//1.将c3p0提供的C3P0-config.xml拷贝src目录下
//2.修改该文件中连接数据库与连接池的相关参数
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("lxlsql");//lxlsql为配置文件中的连接池名
Connection connection = comboPooledDataSource.getConnection();
System.out.println("连接成功");
connection.close();

//手动自行配置连接池配置信息
Properties properties = new Properties();
properties.load(new FileInputStream("src/mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//连接管理由comboPooledDataSource管理,设置连接信息
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
//设置连接池初始化连接数
comboPooledDataSource.setInitialPoolSize(10);
//设置连接池最大连接数
comboPooledDataSource.setMaxConnectionAge(50);
//从连接池中获取连接
Connection connection = comboPooledDataSource.getConnection();
connection.close();
//将连接的引用断开,将连接返回连接池

Druid(德鲁伊)连接池

//1.加入jar包,加入配置文件druid.properties到src目录下
//2.创建Properties对象,读取配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("druid.properties"));
//3.创建一个指定参数的Druid数据库连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
Connection connection = dataSource.getConnection();
System.out.println("连接成功");
connection.close();

Apache-DBUtils使用

基本介绍:commons-dbutils是Apache组织提供一个开源JDBC工具类,能极大简化JDBC编码工作量

DBUtils工具类:

  1. QueryRunner类:封装SQL的执行,线程安全。可实现增删改查、批处理
  2. ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转为另一种格式

ResultSetHandler接口实现类:

在这里插入图片描述

使用流程:

//使用apache-DBUtils工具类 + druid完成对表的crud操作
//1. 得到连接 (druid)
Connection connection = JDBCUtilsByDruid.getConnection();
//2. 使用DBUtils类和接口,先引入DBUtils相关的jar,加入到Project
//3. 创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
//4. 就可以执行相关的方法,返回ArrayList结果集
//注意: sql 语句也可以查询部分列
String sql = "select id, name from actor where id >= ?";
//(1) query 方法就是执行sql语句,得到resultset---封装到 -->ArrayList集合中
//(2) 返回集合
//(3) connection:连接
//(4) sql : 执行的sql语句
List<Actor> list =
        queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
//(5) new BeanListHandler<>(Actor.class): 在将resultset -> Actor 对象 -> 封装到 ArrayList
//    底层使用反射机制去获取Actor类的属性,然后进行封装
//(6) 参数1就是给sql语句中的?赋值,可以有多个值,因为是可变参数Object... params
//(7) 底层得到的PreparedStatment、resultset ,会在query方法关闭
// 输出集合的信息 
for (Actor actor : list) {
    System.out.print(actor);
}
//释放资源
JDBCUtilsByDruid.close(null, null, connection);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值