文章目录
JDBC连接数据库
概述:JDBC(Java Data Base Connectivity),Java数据库连接。Java程序通过JDBC可以操作数据库,实现数据持久化。
JDBC API:官方Sun公司定义的一套操作所有关系型数据库的规则(接口),规范了应用程序和数据库的链接,执行sql语句,并得到返回结果等各种操作,相关的接口和类在java.sql
、javax.sql
中
JDBC使用流程
步骤:
- 注册驱动 -> DriverManager加载Driver类。
- 获取数据库连接 -> 获取Connection连接。
- 获取执行SQL语句对象 -> 获取Statement对象。
- 执行SQL语句并处理返回 -> ResultSet集合存储返回结果集,或返回影响条数。
- 处理结果
- 释放资源
连接数据库方式
// 方法一:通过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接口:
- 用于执行静态SQL语句并返回其生成的结果的对象
- 建立连接之后,需要对数据库进行访问,可以通过:
- 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结果集:
- 表示数据库结果集的数据表,通常由执行数据库查询的语句生成
- ResultSet对象保持一个指针只想其当前的数据行,最初光标位于第一行之前
- next方法将指针移动到下一行,并且由于ResultSet对象中没有下一行时返回false,故可用while循环来遍历结果集
- 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实现事务
基本介绍:
- JDBC中当一个Connection对象创建时,默认情况下自动提交事务,每次执行sql语句成功就会自动提交,无法回滚
- JDBC使用事务使多个sql语句作为一个整体执行
- 调用Connection对象的
setAutoCommit(false)
取消自动提交事务,可以视为开启一个不会自动提交的事务- 当整体的sql语句执行成功后,调用
commit()
提交事务- 当某个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批处理
基本介绍:
当需要成批插入或更新记录时,可以采取批量更新机制,该机制允许多条sql语句一次性提交给数据库批量处理,通常情况下比单独提交更具效率
JDBC批处理机制包括如下方法(Statement对象调用):
addBatch()
添加需批处理的sql
语句executeBatch()
执行批处理语句clearBatch()
清空批处理语句JDBC连接数据库时使用批处理功能,需在url中添加参数:
?rewriteBatchedStatements=true
- 批处理通常与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崩溃,导致需重启数据库。
数据库连接池基本概念:
- 预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从缓冲池中取出一个,使用完毕后返回缓冲池。
- 数据库连接池负责分配、管理、释放数据库连接,它允许应用程序反复使用一个现有的数据库连接,而不是重新建立。
- 当程序向连接池请求的连接数量大于最大连接数量时,未分配连接的请求就会被加入等待队列中。
数据库连接池使用javax.sql.DataSource来表示,该接口由第三方提供实现:
- C3P0,速度较慢,稳定性好(hrbernate、spring)底层使用C3P0
- DBCP,速度较快,稳定性差
- Proxool,可监控连接池状态,稳定性中
- BoneCP速度快
- 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工具类:
- QueryRunner类:封装SQL的执行,线程安全。可实现增删改查、批处理
- 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);