理论知识:

什么是事务?

指作为单个逻辑工作单位执行的一系列操作,要么完全的执行,要么完全不执行。事务处理可以确保非事务性单元内的所有操作都完全完成,否则永久不会更新面向数据的资源。通过将一组操作组合为一个要么成功要么失败的单元,可以简化错误恢复并使应用程序更加可靠。

并发控制概述
事务是并发控制的基本单位,保证事务ACID的特性是事务处理的重要任务,而并发操作有可能会破坏其ACID特性。
DBMS并发控制机制的责任:
对并发操作进行正确调度,保证事务的隔离性更一般,确保数据库的一致性。

事务并发的问题:

(1)脏读:读到另一个事务未提交前的数据。

(2)不可重复读:同一条记录2次读取到的数据不一样。

(3)幻读(虚读):同一个表,2次查询到的数据不一样。

事务的隔离级别:

(1)读,未提交(read uncommited):什么都没解决,性能最好,一般不用。

(2)读已提交数据(read commited):Oracle默认,解决了脏读。

(3)可重复读(repeatable read):Mysql默认,解决了脏读,不可重复读。

(4)串行化(serializable序列化),容易产生死锁。解决所有上述并发问题。

#查询事务隔离级别
SELECT @@tx_isolation;
#修改隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL read UNCOMMITTED ;

 

案例演示:

A向B转账,A金额减少,B金额增加。 若转账中出现问题,则A和B的金额都不变。

public class User {

    private Integer uid;
// private String uid;
private String name;
private String password;
private Double balance; //金额 public Integer getUid() {
return uid;
} public void setUid(Integer uid) {
this.uid = uid;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public Double getBalance() {
return balance;
} public void setBalance(Double balance) {
this.balance = balance;
} @Override
public String toString() {
return "User{" + "uid=" + uid + ", name='" + name + '\'' + ", password='" + password + '\'' + ", balance=" + balance + '}';
}
}

实体类

 <!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--
name:User的相对路径
table:数据库表的名称
-->
<class name="a_helloworld.entity.User" table="t_user">
<!--
一个类标签里面必须有一个id.
hibernate要求实体类有一个属性是唯一值。
column:数据库列名 可以省略,省略的话默认和name的值一样
-->
<id name="uid" column="uid">
<!--
主键的生成策略
native:主键自动增长
uuid:自动生成一个长度为32的字符串
-->
<generator class="native"></generator>
</id>
<!--
其他普通属性
type:一般不去设置 框架会自动对应
not-null:非空
-->
<property name="name"></property>
<property name="password"></property>
<property name="balance"></property>
</class>
</hibernate-mapping>

实体类映射文件

 <!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--1 数据库信息-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate001?characterEncording=UTF-8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property> <!--2 配置hibernate信息 可选部分-->
<!--在控制台输出底层sql语句
项目在开发阶段设置为true 项目发布的时候改成false
因为日志信息会写在文件中(io操作),浪费额外的资源
-->
<property name="show_sql">true</property>
<!--对输出的sql语句进行格式化-->
<property name="format_sql">true</property> <!--hibernate帮助我们创建表的策略需要配置
create:每次执行都重新创建表,数据会丢失
update:如果已经有表,更新。如果没有就创建(一般使用)
create-drop:每次执行都重新创建,数据丢失(开发的时候使用)
validate:校验。每次运行校验数据库表是否正确(不会更新或创建表)
-->
<property name="hbm2ddl.auto">update</property> <!--配置数据库方言
告诉hibernate你用的是什么方言
Mysql:limit
oracle:rownum
让hibernate识别不同数据库的自己特有的语句
-->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property> <!--设置事务隔离级别-->
<property name="hibernate.connection.isolation">4</property> <!--当前session绑定本地线程-->
<property name="hibernate.current_session_context_class">thread</property> <!--3 把映射文件加载-->
<mapping resource="b_Query/entity/User.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>

hibernate核心配置文件

public interface UserService {
public void transfer(Integer from,Integer to,Double money);
}

service层接口

 public class UserServiceImpl implements UserService {
private UserDAO userDAO = new UserDAOImpl();
@Override
public void transfer(Integer from, Integer to, Double money) { Session session = HibernateUtils.getCurrentSession(); /* //验证 session是否相同
Session session1 = HibernateUtils.getCurrentSession();
System.out.println(session == session1);*/ Transaction transaction = session.beginTransaction(); try {
//from 减少金额
userDAO.reduce(from,money); int i =5/0;
//to 增加金额
userDAO.increase(to,money);
transaction.commit();
}catch (Exception e){
e.printStackTrace();
transaction.rollback();
} }
}

service层接口实现

public interface UserDAO {
public void increase(Integer id,Double money);
public void reduce(Integer id,Double money);
}

DAO层接口

public class UserDAOImpl implements UserDAO {
@Override
public void increase(Integer id, Double money) {
Session session = HibernateUtils.getCurrentSession(); User user = session.get(User.class, id);
user.setBalance(user.getBalance()+money);
session.update(user); } @Override
public void reduce(Integer id, Double money) {
Session session = HibernateUtils.getCurrentSession(); User user = session.get(User.class, id);
user.setBalance(user.getBalance()-money);
session.update(user); }
}

DAO层接口实现

public class HibernateUtils {
private static Configuration configure;
private static SessionFactory sessionFactory;
static {
configure = new Configuration().configure();
sessionFactory = configure.buildSessionFactory();
} public static SessionFactory getsessionFactory(){
return sessionFactory;
} //获取session
public static Session getSession(){
return sessionFactory.openSession();
} //拿到和当前线程绑定的session
public static Session getCurrentSession(){
Session currentSession = sessionFactory.getCurrentSession();
return currentSession;
}
}

hibernate工具类

public class BalanceDemo {
@Test
public void transfer(){
UserService userService = new UserServiceImpl();
userService.transfer(2,1,5.0);
}
}

测试类

在业务层如果转账过程中出现了问题,事务回滚,可以保证数据库的一致性。

转账前的记录:

处理业务时产生异常:

这时后刷新记录发现记录中的balance字段(表示金额)数值不变。业务逻辑实现类中,转账后捕获到了异常事务进行了回滚。

若没有产生异常,则两条记录的金额都发生变化。

注意:

1.在hibernate.cfg.xml核心配置文件中可以配置事务隔离级别  4表示repeatable read

<property name="hibernate.connection.isolation">4</property>

2.在DAO层操作数据库需要用到session,在service层获取事务也需要session,我们要确保2个session为同一个对象

解决:将session与本地线程绑定。

需要在hibernate.cfg.xml核心配置文件中配置

<!--当前session绑定本地线程-->
<property name="hibernate.current_session_context_class">thread</property>

Hibernate中事务小案例的更多相关文章

  1. JavaWeb_(Hibernate框架)Hibernate中事务

    Hibernate中事务 事务的性质 事物的隔离级别 配置事务的隔离级别 事务的性质 原子性:原子,不可再分,一个操作不能分为更小的操作,要么全都执行,要么全不执行. 一致性:事务在完成时,必须使得所 ...

  2. Hibernate中事务的隔离级别设置

    Hibernate中事务的隔离级别,如下方法分别为1/2/4/8. 在Hibernate配置文件中设置,设置代码如下

  3. Hibernate中事务声明

    Hibernate中JDBC事务声明,在Hibernate配置文件中加入如下代码,不做声明Hibernate默认就是JDBC事务. 一个JDBC 不能跨越多个数据库. Hibernate中JTA事务声 ...

  4. 关于Unity中的小案例之运动的小船以及摄像机跟随技术(专题五)

    实例步骤 1.创建Unity项目和文件目录,保存场景 场景搭建 2.导入美术做好的资源包(第68) a: 导入地形资源包terrain.unitypackage,把里面的Map/Prefabs/Ter ...

  5. js中的小案例(一)

    效果图: html代码: <div id="date"> <p> <span id="prev">上一月</span& ...

  6. 七、hibernate的事务使用

    hibernate中事务隔离级别 1:读未提交 2:读已提交 4:可重复读 8:可串行化 hibernate事务使用 在核心配置文件中配置事务隔离级别 <property name=" ...

  7. Hibernate中的配置对象

    数据库连接:由 Hibernate 支持的一个或多个配置文件处理.这些文件是 hibernate.properties 和 hibernate.cfg.xml. 类映射设置:这个组件创造了 Java ...

  8. Hibernate的介绍及入门小案例

    1.Hibernate的诞生 在以前使用传统的JDBC开发应用系统时,如果是小型应用系统,并不觉得有什么麻烦,但是对于大型应用系统的开发,使用JDBC就会显得力不从心,例如对几十,几百张包含几十个字段 ...

  9. (八) Hibernate中的Session以及事务

    HibernateUtil.getSessionFactory().getCurrentSession() 和HibernateUtil.getSession() 的区别: 1.异:getCurren ...

随机推荐

  1. new function

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  2. Flask-Moment----探索

    前言:  Flask-Moment在所有的flask扩展中算是相对简单的一个了,但是还是有很多需要理解的地方.那么今天就跟着笔者一起,来学习一下flask-moment在flask项目中的应用. 首先 ...

  3. block,inline,inline-block的区别

    最近正在复习,紧张地准备几天后的笔试,然后刚好看到这个地方. block:块级元素,会换行,如div,p,h1~h6,table这些,可以设置宽高:    inline:行内元素,不换行,挤在一行显示 ...

  4. PHP输出打印方法

    PHP这门语言灵活而充满众多的API和用法,然而在这个技术领域里却缺乏一些系统的总结归纳.或许这与PHP语言的诞生方式有关,衍生,快速变化,原始限制等等,诸多因素决定这门语言变得smarty,却没有人 ...

  5. Zabbix 3.0 监控Web

    zabbix 界面配置 触发器添加

  6. 织梦去除版权中的Power by DedeCms

    找到文件 \include\dedesql.class.php 注释或删除下面代码,大概在588行 $arrs1 = array(0x63,0x66,0x67,0x5f,0x70,0x6f,0x77, ...

  7. 【NOIP2015】运输计划

    [NOIP2015]运输计划 标签: 树上差分 LCA 二分答案 Description 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星 ...

  8. 试着把.net的GC讲清楚(2)

    试着把.net的GC讲清楚(1) 上篇文章说了一些基本概念的东西,然后还有很多东西概念没有头绪,这篇文章我试着解释 GC的回收算法详细步骤? 上篇]文章讲了.net GC的算法是Mark and Co ...

  9. Java SocketChannel 读取ByteBuffer字节的处理模型

    在JAVA中的流分为字节流或字符流,一般来说采用字符流处理起来更加方便.字节流处理起来相对麻烦,SocketChannel中将数据读取到ByteBuffer中,如何取出完整的一行数据(使用CRLF分隔 ...

  10. Entity Framework——记录执行的命令信息

    有两种方法可以记录执行的SQl语句: 使用DbContext.Database.Log属性 实现IDbCommandInterceptor接口 一 使用DbContext.Database.Log属性 ...