笔记:JDBC(二)——批处理/事务/连接池

一、批处理

    概念:将向数据库表一次性插入多条记录,而不是一条一条插入的方式,这样可以提供效率。

    实现方法:

                executeBatch():向MySQL数据库发送一批SQL语句
                addBatch():将当前SQL语句添加到Statement对象中
                clearBatch():释放Statement对象中的SQL语句
  • Statement批处理,该类提供如下方法用于批处理操作。

方法摘要

void

addBatch(String sql)
将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。

void

clearBatch()
清空此 Statement 对象的当前 SQL 命令列表。

int[]

executeBatch()
将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组。

 
  • PreparedStatement批处理,该类提供如下方法用于批处理操作。

方法摘要

void

addBatch()
将一组参数添加到此 PreparedStatement 对象的批处理命令中。

 
二、事务
    定义:访问并可能更新数据库中各种数据项的一个程序执行单元。
 
    四大特点(简称ACID):
      原子性(Atomicity):一个事务不可分割的工作单位,事务中包括的诸操作要么都执行(成功),要么都不执行(失败)。
      一致性(Consistent):事务必须是使数据库从一个一致性状态变到另一个一致性状态,一致性与原子性是密切相关的。
      隔离性(Isolation):一个事务执行不能被其他事务干扰。
      持久性(Durability):持久性也称为永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
 
 
三、MySQL事务
    概念:MySQL对事物的管理,在默认情况下,MySQL每执行一条SQL语句,就会将这条SQL语句视为一个单独的事物。如果在多条SQL语句在一个事物的情况下,MySQL默认情况是无法完成的。
  • start transaction命令:表示开启事务。
  • rollback命令:表示回滚事务。如果选择回滚事务的话,数据将恢复到事物开启之前的状态。
  • commit命令:表示提交事务。如果选择提交事务的话,数据更新之后将无法恢复。

 

四、JDBC事务
    

  上面是在MySQL数据库中管理事务,在实际开发中,更多是在Java代码中管理MySQL的事务。也就是说,是利用JDBC来管理MySQL事务。JDBC提供如下三种方法来管理MySQL事务:

方法摘要

void

commit()
使自从上一次提交/回滚以来进行的所有更改成为持久更改,并释放此 Connection 对象当前保存的所有数据库锁定。

void

rollback()
取消在当前事务中进行的所有更改,并释放此 Connection 对象当前保存的所有数据库锁定。

void

setAutoCommit(boolean autoCommit)
将此连接的自动提交模式设置为给定状态。

 

    MySQL事务的回滚操作,默认是回滚到开启事务之前的数据状态。但在实际开发中,经常需要数据回滚到某个指定的执行状态。MySQL提供了回滚点(Savepoint)的概念,回滚点类似于游戏中的存档。也就是说,设置回滚点后,可以将事务回滚到指定某个回滚点的数据状态。下表是回滚点提供的相关方法:

方法摘要

void

releaseSavepoint(Savepoint savepoint)
从当前事务中移除给定 Savepoint 对象。

void

rollback(Savepoint savepoint)
取消设置给定 Savepoint 对象之后进行的所有更改。

Savepoint

setSavepoint()
在当前事务中创建一个未命名的保存点 (savepoint),并返回表示它的新 Savepoint 对象。

Savepoint

setSavepoint(String name)
在当前事务中创建一个具有给定名称的保存点,并返回表示它的新 Savepoint 对象。

 
五、事务隔离级别  

  在日常MySQL的事务管理中,如果多线程开启各自事务操作,而数据库不负责隔离操作时,经常会出现以下三种常见问题:

  • 脏读:指一个事务读取到另一个事务未提交的数据记录。

脏读这种操作在实际是非常危险的。例如如果B给A转账10000元钱,B开启一个事务用于转账10000元,实际操作后并未提交事务。如果此时A查询自己的账户会发现已经收到B转账的10000元,当A做出实际动作(发货)后,B再将事务回滚,最终导致A损失10000元钱。

  • 不可重复读:指一个事务中读取指定表中的某一条数据,多次读取结果不同。

例如如果A第一次查询账户为20000元钱后,B向A转账10000元钱,A在第二次查询账户为30000元钱。前后两次查询结果不一致,A可能不知道多出的10000元钱是来自哪里。

不可重复读与脏读的区别在于脏读读取的是前一事务未提交的数据,而不可重复读读取的是前一事务提交的数据。

  • 幻读(虚读):指一个事务中读取到另一个事务插入的数据,导致前后读取结果不一致。

例如酒店统计房间预订数量时,第一次统计为101间被预订,A在酒店第一次统计后,预订了110房间,酒店在A成功预订110房间后第二次统计,结果为102间被预订。导致酒店前后统计数量不一致。

幻读与不可重复读的区别在于不可重复读读取的是另一个事务的更新操作,而幻读读取的是另一个事务的插入操作(MySQL数据库无法测试到幻读问题)。

针对上述的三个问题,MySQL数据库提供了四大隔离级别来解决,这四大隔离级别分别为:

  • SERIALIZABLE(串行化)

这个隔离级别可避免脏读、不可重复读、虚读情况的发生。

  • REPEATABLE READ(可重复读)

这个隔离级别可避免脏读、不可重复读情况的发生。

  • READ COMMITTED(读已提交数据)

这个隔离级别可避免脏读情况发生。

  • READ UNCOMMITTED(读未提交数据)

这个隔离级别最低级别,以上情况均无法保证。

  • 四个隔离级别的优先级:

SERIALIZABLE –> REPEATABLE READ -> READ COMMITTED -> READ UNCOMMITTED

  • 四个隔离级别的性能:

READ UNCOMMITTED -> READ COMMITTED -> REPEATABLE READ -> SERIALIZABLE

 
七、数据库连接池
  概述:连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。这种把连接“汇集”起来的技术基于这样的一个事实:对于大多数应用程序,当它们正在处理通常需要数毫秒完成的事务时,仅需要能够访问JDBC连接的 1 个线程。当不处理事务时,这个连接就会闲置。相反,连接池允许闲置的连接被其它需要的线程使用。

连接池可以极大的改善用户的 Java 应用程序的性能,同时减少全部资源的使用。连接池主要的优点有:

  • 减少连接创建时间。
  • 简化的编程模式。
  • 受控的资源使用。
  常见的第三方连接池:
    1、DBCP     

      DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目。单独使用dbcp需要3个包:commons-dbcp.jar,commons-pool.jar,commons-collections.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。

    2、C3P0

      C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。

      C3P0与DBCP的区别:

              dbcp没有自动回收空闲连接的功能。

          c3p0有自动回收空闲连接功能。

    3、JNDI

     NDI(Java Naming and Directory Interface)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI API的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互。集群JNDI实现了高可靠性JNDI,通过服务器的集群,保证了JNDI的负载平衡和错误恢复。在全局共享的方式下,集群中的一个应用服务器保证本地JNDI树的独立性,并拥有全局的JNDI树。每个应用服务器在把部署的服务对象绑定到自己本地的JNDI树的同时,还绑定到一个共享的全局JNDI树,实现全局JNDI和自身JNDI的联系。

JNDI(Java Naming and Directory Interface)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口,类似JDBC都是构建在抽象层上。

JNDI(Java Naming and Directory Interface)是允许将一个Java对象绑定到一个JNDI容器(tomcat)中 ,并且为对象指定一个名称,通过javax.naming 包 Context 对JNDI 容器中绑定的对象进行查找,通过指定名称找到绑定Java对象。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。