Connection类的简单使用
一、Connection类的简介是java API中提供的一个接口它的实现类由其他厂商完成,用来与数据库的连接这个接口可以调用方法,来获得SQL语句的对象(Statement、PreparedStatement)其中Statement接口本身使用较少,而它的子接口PreparedStatement 却经常使用PreparedStatement 比 Statement 更安全,没有SQL注入的问题它
·
目录
一、Connection类的简介
- 是java API中提供的一个接口
- 它的实现类由其他厂商完成,用来与数据库的连接
- 这个接口可以调用方法,来获得SQL语句的对象(Statement、PreparedStatement)
- 其中Statement接口本身使用较少,而它的子接口PreparedStatement 却经常使用
- PreparedStatement 比 Statement 更安全,没有SQL注入的问题
- 它的实例对象表示一条预编译过的 SQL 语句
- 可以发送SQL语句到数据库
- 其中Statement接口本身使用较少,而它的子接口PreparedStatement 却经常使用
二、常用方法
1. 资源的关闭
void close()
- 手动关闭Connection资源
boolean isClosed()
- 检索此 Connection 对象是否已经被关闭
2. 创建PreparedStatement对象
PreparedStatement prepareStatement(String sql)
- 创建 PreparedStatement 对象,方便将 SQL 语句发送到数据库
// 还有好几个重载的方法可以创建PreparedStatement的对象,但是使用较少
3. 只读模式
void setReadOnly(boolean readOnly)
- 设置此 Connection 对象是否处于只读模式
boolean isReadOnly()
- 检索此 Connection 对象是否处于只读模式
4. 自动提交
boolean getAutoCommit()
- 查询此 Connection 对象的自动提交的状态
void setAutoCommit(boolean autoCommit)
- 设置此 Connection 对象的自动提交的状态
void commit()
- 取消自动提交后,需要手动提交sql语句
/*
1. 经常使用的是取消自动提交,取消自动提交的应用场景:
- 事务处理:可以避免出现"脏数据"
- 批量处理:可以提高批量处理数据的效率
2. 取消自动提交的目的就是保持数据的完整性
- 一个系统的更新操作可能需要多个SQL语句进行操作
- 一般在开始时手动设置setAutoCommit(false),等全部的 SQL语句正常执行完后,再手动进行commit()
- 如果中间出现错误,可以在catch()中进行rollback(),取消这一次的全部操作,避免了脏数据
- 这样即使更新数据的时候报错,更新的内容也不会提交到数据库中
- 而如果没有手动的进行setAutoCommit(false),或忘记了回滚数据
- 出错时就会造成,前几条SQL语句执行,后几条没有执行
*/
5. 隔离级别
int getTransactionIsolation()
- 查询此 Connection 对象的当前事务的隔离级别
void setTransactionIsolation(int level)
- 设置此 Connection 对象的当前事务的隔离级别
6. 保存点
Savepoint setSavepoint()
- 在当前事务中创建一个未命名的保存点 (savepoint),并返回表示它的 Savepoint 对象。
Savepoint setSavepoint(String name)
- 在当前事务中创建一个具有给定名称的保存点,并返回表示它的 Savepoint 对象。
void releaseSavepoint(Savepoint savepoint)
- 从当前事务中移除给定 Savepoint 对象
7. 回滚
void rollback()
- 回滚,意思就是数据库做修改之后未 commit 之前, 使用 rollback 可以恢复数据到修改之前
void rollback(Savepoint savepoint)
- 回滚到保存点,可以恢复数据到Savepoint的位置
三、常用方法的演示
1. 资源的关闭
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 1. 未关闭资源时,获取的状态是false
System.out.println(conn.isClosed()); // false
// 2. 手动关闭资源
conn.close();
// 3. 关闭资源后,获取的状态是true
System.out.println(conn.isClosed()); // true
}
2. 获取 PreparedStatement 对象
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 调用方法,得到PreparedStatement对象
// 注意:PreparedStatement也需要进行资源的关闭
PreparedStatement ps = conn.prepareStatement("这里填入SQL语句");
conn.close();
ps.close();
}
3. 只读模式
(1) 方法的简单使用
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 1. 查询结果为"false",说明默认情况下不是只读状态,可以更新数据
System.out.println(conn.isReadOnly());
// 2. 设置为只读状态
conn.setReadOnly(true);
// 3. 更新设置后,查询结果为"true"
System.out.println(conn.isReadOnly());
// 4. 关闭资源
conn.close();
}
(2) 只读模式下读取数据
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 1. 设置为只读状态
conn.setReadOnly(true);
// 2. 获取SQL语句的预编译状态,PreparedStatement的对象
String sql = "select count(*) from user_table";
PreparedStatement ps = conn.prepareStatement(sql);
// 3. 执行查询操作
boolean b = ps.execute();
// 4. 是否查询成功
System.out.println(b); // 结果为"true",即读取数据成功
// 5. 关闭资源
ps.close();
conn.close();
}
(3) 只读模式下更新数据
// 抛异常:
// java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
// 异常:当前连接处于只读状态,对数据进行修改的查询操作是不被允许的
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 1. 设置为只读状态
conn.setReadOnly(true);
// 2. 获取SQL语句的预编译状态,PreparedStatement的对象
String sql = "truncate user_table";
PreparedStatement ps = conn.prepareStatement(sql);
// 3. 执行更新操作
boolean b = ps.execute();
// 4. 是否更新成功
System.out.println(b); // 结果为"true",即读取数据成功
// 5. 关闭资源
ps.close(); // 为了方便,这里用throws处理异常
conn.close();
}
4. 自动提交
(1) 方法的简单使用
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 1. 结果为"true",说明默认是自动提交的状态
System.out.println(conn.getAutoCommit());
// 2. 取消自动提交
conn.setAutoCommit(false);
// 3. 结果为"false"
System.out.println(conn.getAutoCommit());
// 4. 关闭资源
conn.close(); // 为了方便,这里用throws处理异常
}
(2) 没有取消自动提交、中间没有出错行为
// 两次操作均正常执行
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 第一次操作
String sql1 = "insert into user_table(`id`, `password`, `balance`)values(?, ?, ?)";
PreparedStatement ps1 = conn.prepareStatement(sql1);
ps1.setObject(1, 4);
ps1.setObject(2, "123456");
ps1.setObject(3, 10000);
ps1.execute();
// 第二次操作
String sql2 = "insert into user_table(`id`, `password`, `balance`)values(?, ?, ?)";
PreparedStatement ps2 = conn.prepareStatement(sql2);
ps2.setObject(1, 5);
ps2.setObject(2, "123456");
ps2.setObject(3, 10000);
ps2.execute();
ps2.close();
ps1.close();
conn.close();
}
(3) 没有取消自动提交、中间有出错的行为
// 中间有一个 "5 / 0" 的行为,直接导致第二次操作无法执行,使得只有第一次操作被成功执行
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 第一次操作
String sql1 = "insert into user_table(`id`, `password`, `balance`)values(?, ?, ?)";
PreparedStatement ps1 = conn.prepareStatement(sql1);
ps1.setObject(1, 4);
ps1.setObject(2, "123456");
ps1.setObject(3, 10000);
ps1.execute();
System.out.println(5 / 0); // 这里出错,下面的语句就不会执行,但是上面的语句已经执行,这不是我们想要的
// 第二次操作
String sql2 = "insert into user_table(`id`, `password`, `balance`)values(?, ?, ?)";
PreparedStatement ps2 = conn.prepareStatement(sql2);
ps2.setObject(1, 5);
ps2.setObject(2, "123456");
ps2.setObject(3, 10000);
ps2.execute();
ps2.close();
ps1.close();
conn.close();
}
(4) 取消自动提交、中间有出错行为
// 第一次操作之后,出现 "5 / 0" 的错误,使得第二次操作无法执行
// 而又因为取消了自动提交,所以第一次操作是无效的
@Test
public void test() {
Connection conn = null;
PreparedStatement ps1 = null;
PreparedStatement ps2 = null;
try {
conn = Utils_01.getConnection();
// 取消自动提交
conn.setAutoCommit(false);
// 第一次操作
String sql1 = "insert into user_table(`id`, `password`, `balance`)values(?, ?, ?)";
ps1 = conn.prepareStatement(sql1);
ps1.setObject(1, 4);
ps1.setObject(2, "123456");
ps1.setObject(3, 10000);
ps1.execute();
System.out.println(5 / 0);
// 第二次操作
String sql2 = "insert into user_table(`id`, `password`, `balance`)values(?, ?, ?)";
ps2 = conn.prepareStatement(sql2);
ps2.setObject(1, 5);
ps2.setObject(2, "123456");
ps2.setObject(3, 10000);
ps2.execute();
// 手动提交
conn.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭Connection资源之前,修改状态为默认的自动提交
// 主要针对数据库连接池的操作
try {
conn.setAutoCommit(true);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
// 关闭资源:为了方便,这里仅简单处理异常
try {
ps2.close();
ps1.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
(5) 批量处理数据
- 批量处理数据有更好的方法,请移步批量插入数据
// 因为每一次再提交数据的时候,都会有时间的消耗
// 而先执行完所有操作,再进行提交,可以减少很多不必要的时间消耗
// 可以发现取消自动提交后,时间消耗由9s直接缩短为1s
// 1. 没有取消自动提交
@Test
public void test1() throws Exception {
Connection conn = Utils_01.getConnection();
PreparedStatement ps = null;
long start = System.currentTimeMillis();
for (int i = 1; i <= 10000; i++) {
String sql1 = "insert into user_table(`id`, `password`, `balance`)values(?, ?, ?)";
ps = conn.prepareStatement(sql1);
ps.setObject(1, i * 10);
ps.setObject(2, "123456");
ps.setObject(3, 10000);
ps.execute();
}
long end = System.currentTimeMillis();
System.out.println(end - start); // 9842ms
ps.close();
conn.close();
}
// 2. 取消自动提交
@Test
public void test2() {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = Utils_01.getConnection();
conn.setAutoCommit(false);
long start = System.currentTimeMillis();
for (int i = 1; i <= 10000; i++) {
String sql1 = "insert into user_table(`id`, `password`, `balance`)values(?, ?, ?)";
ps = conn.prepareStatement(sql1);
ps.setObject(1, i * 10);
ps.setObject(2, "123456");
ps.setObject(3, 10000);
ps.execute();
}
conn.commit();
long end = System.currentTimeMillis();
System.out.println(end - start); // 954ms,效率明显提高
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源前,恢复为自动提交
try {
conn.setAutoCommit(true);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
ps.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
5. 隔离级别
/**
* JDBC定义了五种事务隔离级别:
* TRANSACTION_NONE = 0; 驱动不支持事务
* TRANSACTION_READ_UNCOMMITTED = 1; 三种并发问题都会发生,允许脏读、不可重复读和幻读
* TRANSACTION_READ_COMMITTED = 2; 只解决了脏读问题,禁止脏读,但允许不可重复读和幻读
* TRANSACTION_REPEATABLE_READ = 4; 解决了脏读、不可重复读,但允许幻读
* TRANSACTION_SERIALIZABLE = 8; 禁止脏读、不可重复读和幻读,隔离级别最高,但效率最低
*/
@Test
public void test() throws Exception {
Connection conn = Utils_01.getConnection();
// 1. 结果为"4",说明默认的隔离级别为"TRANSACTION_REPEATABLE_READ"
System.out.println(conn.getTransactionIsolation());
// 2. 设置隔离级别为"TRANSACTION_READ_COMMITTED",这个级别是常用的
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
// 3. 结果为"2"
System.out.println(conn.getTransactionIsolation());
// 4. 关闭资源
conn.close();
}
6. 保存点与事务回滚
/**
* 回退
* 1.设置保存点 savepoint a
* 2.取消自动提交
* 3. 在提交之前进行回滚,必须是没有commit前使用
* - 如果事务已经提交,那么无论设置多少保存点,都统统消失
* - 如果关闭了自动提交,那么必须手动commit()
* 4. 回退到保存点后,他后面的操作即使是正确的也不会被执行
*/
// 下面的代码:四次操作执行完后,遇到了"5 / 0" 的错误行为,进入catch(),回滚到保存点后再提交事务
// 故,只有第一次、第二次操作起效果,剩余两次无效果
@Test
public void test() {
Connection conn = null;
Savepoint sp = null;
try {
conn = Utils_01.getConnection();
conn.setAutoCommit(false);
// 第1次更新数据
String sql1 = "update user_table set `password` = 'AAA1' WHERE `id` = 1";
PreparedStatement ps1 = conn.prepareStatement(sql1);
ps1.execute();
// 第2次更新数据
String sql2 = "update user_table set `password` = 'BBB2' WHERE `id` = 2";
PreparedStatement ps2 = conn.prepareStatement(sql2);
ps2.execute();
// 保存点
sp = conn.setSavepoint("第一个保存点");
String sql3 = "update user_table set `password` = 'CCC3' WHERE `id` = 3";
PreparedStatement ps3 = conn.prepareStatement(sql3);
ps3.execute();
// 第4次数据
String sql4 = "update user_table set `password` = 'DDD4' WHERE `id` = 4";
PreparedStatement ps4 = conn.prepareStatement(sql4);
ps4.execute();
// 三次操作均执行后,出现错误,进入catch()
System.out.println(5 / 0);
// 如果没有出错,在这里手动提交
conn.commit();
} catch (Exception e) {
System.out.println("出错就回滚");
try {
// 回滚事务到保存点
conn.rollback(sp);
// 出错之后,在这里手动提交
conn.commit();
} catch (SQLException throwables) {
System.out.println("回滚出错");
throwables.printStackTrace();
}
}
}
四、综合演示
@Test
public void test() {
Connection conn = null;
PreparedStatement ps = null;
Savepoint savepoint = null;
try {
// 1. 获取连接
conn = Utils_01.getConnection();
// 2. 设置只读模式,之后就不可以进行更新操作,为了下面的操作,这里不开启了
// conn.setReadOnly(true);
// 3. 取消自动提交
conn.setAutoCommit(false);
// 4. 设置隔离级别,使得仅避免脏读问题
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
// 5. 设置保存点
savepoint = conn.setSavepoint("XX");
// 6. 预编译
String sql = "insert into user_table(`id`, `password`, `balance`) values (?, ?, ?)";
ps = conn.prepareStatement(sql);
ps.setObject(1, 2);
ps.setObject(2, "DFG");
ps.setObject(3, 100);
// 7. 执行SQL语句
ps.execute();
// 8. 提供错误语句,方便回滚操作
System.out.println(5 / 0);
// 9. 手动提交事务
conn.commit();
System.out.println("正常执行后,手动提交事务");
}
catch (Exception e) {
try {
System.out.println("出现异常,回滚到保存点");
conn.rollback(savepoint);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
System.out.println("出现异常,手动提交事务");
conn.commit();
} catch (SQLException ee) {
ee.printStackTrace();
}
}
finally {
if (ps != null) {
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
更多推荐
已为社区贡献3条内容
所有评论(0)