日新计划6月更文 Day 23
JDBC~~(Java Database Connectivity)~~是一个独立于特定数据库管理系统,通用的数据库存取操作的应用编程接口。
建立连接
最简单的建立与MySQL数据库连接的方法如下:
Driver driver = new com.mysql.cj.jdbc.Driver();
Properties info = new Properties();
info.setProperty("user", userName);
info.setProperty("password", password);
Connection conn = driver.connect(url, info);
为了提高程序可移植性,可使用反射创建驱动对象。
使用驱动管理器可以简化部分操作:
DriverManager.registerDriver(driver); // 可省略,会随Driver加载自动完成
Connection conn = DriverManager.getConnection(url, info);
为实现解耦,通过配置文件获得连接信息,最终代码为:
// 读取配置文件
InputStream is = Main.class.getResourceAsStream("jdbc.cfg");
Properties prop = new Properties();
prop.load(is);
String url = prop.getProperty("url");
String userName = prop.getProperty("userName");
String password = prop.getProperty("password");
String device = prop.getProperty("device");
// 加载驱动
Class.forName(device);
// 连接
Connection conn = DriverManager.getConnection(url, userName, password);
//断开连接
conn.close();
操作和访问数据库
操作和访问数据库的方式有以下三种:
Statement:用于执行静态SQL语句并返回执行结果对象。
由于存在SQL注入等安全问题和操作繁琐等缺点,
已不再使用。PreparedStatement:用于存储预编译的SQL语句,可多次高效地执行这些SQL语句
CallableStatement:用于执行SQL存储过程。
PreparedStatement的使用
与Statement相比,PreparedStatement使用预编译的SQL语句并通过占位符代替变量,具有以下优点:
- 解决了SQL注入的安全问题
- 可操作Blob数组
- 实现更高效的批量操作
PreparedStatement对数据库的操作(增删改)基本符合以下的步骤:
String sql = "insert into Beauty(Name) values (?);"; // 以“?”作为占位符
PreparedStatement sm = conn.prepareStatement(sql);
sm.setString(1, value); // 填充占位符,从1开始
sm.addBatch(); // 暂存待执行的SQL语句
sm.execute(); // 执行SQL语句
sm.close();
如果需要对数据进行查询,可以使用executeQuery()执行SQL语句并获得结果集:
ResultSet rs = sm.executeQuery();
ResultSetMetaData rsMetaData = rs.getMetaData(); // 获取结果集的元数据
rs.close(); // 需要手动关闭
对结果集的访问可以使用迭代器,对结果集数据的存储一般使用ORM(Object Relational Mopping):
- 数据表<-->Java类
- 记录<-->对象
- 字段<-->对象属性
MySQL数据类型与Java数据类型对应关系
| Java数据类型 | MySQL数据类型 |
|---|---|
| boolean | BIT |
| byte | TINYINT |
| short | SMALLINT |
| int | INTEGER |
| long | BIGINT |
| String | CHAR,VARCHAR,LONGVARCHAR |
| byte array | BINARY,VAR BINARY |
| java.sql.Date | DATE |
| java.sql.Time | TIME |
| java.sql.Timestamp | TIMESTAMP |
事务操作
事务:使数据从一种状态转换到另一种状态的一组逻辑操作单元 事务操作:保证所有操作都作为一个工作单元处理。在执行事务的时候,要么所有事务都被提交(commit),要么数据库管理系统放弃所有操作,整个事务回滚(rollback)。
事务的ACID属性
- Atomicity:原子性,事务为一个不可分割的基本单元
- Consistency:一致性,事务必须使数据库从一个一致的转台变换到另一个一致的状态
- Isolation:隔离性,事务的执行相互隔离,并发的各个事务不会相互干扰
- Durability:持久性,事务被提交后其对数据库的更改为永久性的,后续的操作或数据库故障不会对其产生影响
数据库并发问题
对于并发的事务,当其操作同一数据且未作相应措施时,会出现一些问题:
- 脏读:B读取了被A修改但未提交的数据,若A回滚,则B读取的数据有误
- 不可重复读:A两次读取同一数据之间该数据已被B修改
- 幻读:A读取某张表的过程中B增/删了部分数据
数据库的隔离级别
为了在保证隔离性的同时保证一定的并发性,需要在数据库的隔离级别中做出取舍:
- READ UNCOMMITED:读未提交数据,允许读取未被其他事务提交的数据
- READ COMMITED:读已提交数据,仅允许读取已被其他事务提交的数据
- REPEATABLE READ:可重复读,确保事务可多次对同一字段读取到相同的值
- SERIALIZABLE:串行化,确保一个事务执行期间可在表中读取到相同的数据
其中 Oracle 仅支持 READ COMMITED 和 SERIALIZABLE,默认为 READ COMMITED;MySQL 支持四种隔离级别,默认为 REPEATABLE READ。
在JDBC中通过以下方法管理数据库隔离级别:
conn.getTranactionIsolation(); // 获取当前隔离级别
conn.setAutoCommit(false); // 关闭自动提交
conn.setTranactionIsolation(Connection.); // 设置隔离级别