Hibernate中事务小案例
理论知识:
什么是事务?
指作为单个逻辑工作单位执行的一系列操作,要么完全的执行,要么完全不执行。事务处理可以确保非事务性单元内的所有操作都完全完成,否则永久不会更新面向数据的资源。通过将一组操作组合为一个要么成功要么失败的单元,可以简化错误恢复并使应用程序更加可靠。
事务并发的问题:
(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中事务小案例的更多相关文章
- JavaWeb_(Hibernate框架)Hibernate中事务
Hibernate中事务 事务的性质 事物的隔离级别 配置事务的隔离级别 事务的性质 原子性:原子,不可再分,一个操作不能分为更小的操作,要么全都执行,要么全不执行. 一致性:事务在完成时,必须使得所 ...
- Hibernate中事务的隔离级别设置
Hibernate中事务的隔离级别,如下方法分别为1/2/4/8. 在Hibernate配置文件中设置,设置代码如下
- Hibernate中事务声明
Hibernate中JDBC事务声明,在Hibernate配置文件中加入如下代码,不做声明Hibernate默认就是JDBC事务. 一个JDBC 不能跨越多个数据库. Hibernate中JTA事务声 ...
- 关于Unity中的小案例之运动的小船以及摄像机跟随技术(专题五)
实例步骤 1.创建Unity项目和文件目录,保存场景 场景搭建 2.导入美术做好的资源包(第68) a: 导入地形资源包terrain.unitypackage,把里面的Map/Prefabs/Ter ...
- js中的小案例(一)
效果图: html代码: <div id="date"> <p> <span id="prev">上一月</span& ...
- 七、hibernate的事务使用
hibernate中事务隔离级别 1:读未提交 2:读已提交 4:可重复读 8:可串行化 hibernate事务使用 在核心配置文件中配置事务隔离级别 <property name=" ...
- Hibernate中的配置对象
数据库连接:由 Hibernate 支持的一个或多个配置文件处理.这些文件是 hibernate.properties 和 hibernate.cfg.xml. 类映射设置:这个组件创造了 Java ...
- Hibernate的介绍及入门小案例
1.Hibernate的诞生 在以前使用传统的JDBC开发应用系统时,如果是小型应用系统,并不觉得有什么麻烦,但是对于大型应用系统的开发,使用JDBC就会显得力不从心,例如对几十,几百张包含几十个字段 ...
- (八) Hibernate中的Session以及事务
HibernateUtil.getSessionFactory().getCurrentSession() 和HibernateUtil.getSession() 的区别: 1.异:getCurren ...
随机推荐
- Linux 下编写服务器程序时关于Address already in use 的小错误
新手,,学习linux服务器编程的时候,bind()函数出现了Address already in use 的错误,这是因为上一次bind过后,还未释放,,只要在socket和bind之间加一个函数就 ...
- iPad Pro 10.5+Apple Pencil之专注文献阅读与笔记效率的App综述
先谈谈我对笔记类App的几点要求--原则是取其精华,略其糟粕,毕竟开发者们还在,App就会不断地被改进: 增删快捷方便:如完美支持Apple Pencil,特定场景下强大的录音功能,单词或短句涂改即可 ...
- Composer 结合 Git 创建 “服务类库”
Composer 结合 Git 创建 "服务类库" 我一直认为,现在的 PHP 已经进展到了工程化的领域.以前的 PHP 开发者,以快为美,速度和规模永远都是矛盾体.现在的 PHP ...
- linux使用i/o内存访问外设
一.linux中访问外设的方法. 1.IO端口(IO port) linux系统给外设分配不同的端口号,linux利用端口号来访问设备(驱动) (cpu x86) cpu访问外设通过端号,访问通过地址 ...
- MathJax使用指南
MathJax使用指南 SublimePrettyJson Github CSDN-Markdown语法集锦 LaTex 简明教程 在Markdown中输入数学公式(MathJax) MathJax ...
- 在CentOS下安装crontab服务
1. 确认crontab是否安装: 执行 crontab 命令如果报 command not found,就表明没有安装 2. 安装 crontab 执行 yum install -y vixie-c ...
- href与src 区别
src 是可替换的文本支撑,将指向的内容引入文档当前标签所在的位置, 当浏览器解析到该标签时,将暂停其它资源的下载处理, 请求该标签的src ,下载指向的外部资源并应用到当前文档, 所以js 脚本一般 ...
- C/C++语言简介之运算符
比较特别的是,比特右移(>>)运算符可以是算术(左端补最高有效位)或是逻辑(左端补 0)位移.例如,将 11100011 右移 3 比特,算术右移后成为 11111100,逻辑右移则为 0 ...
- 解决react-router4在browserhistory路由下的nginx的白屏或者404问题
使用react-router,官方推荐用browserhistory,美观简洁.但是nginx服务器端的配置也让人头疼. 首先看官方举例的方法: server { location / { try_f ...
- 手把手教你树莓派实现简易室内监控系统(A)
第一次写博文,有很多疏漏之处,然后受逼乎影响较深,希望大家多多包涵! _______________________________________________分割线是这样画的吧_________ ...