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 ...
随机推荐
- valgrind安装与使用
1.得到源代码:http://valgrind.org/->source code 下载最新版的valgrind得到:valgrind-3.2.3.tar.bz2 2.解压安装包:tar -jx ...
- tcp 网络编程
网络编程同时也是进程间的一种通信:服务器进程和应用进程间的通信. OSI:开放式系统互联 OSI 7层模型: ...
- js压缩上传图片
初学有不当之处,请多多指点, <body> <div class="cc"> <input type="file" id=&quo ...
- shell编程值之shell流程控制(7)
条件判断式 1 按照文件类型判断(常用类型) 测试类型 作用 -d 文件 判断该文件是否存在,并且是否为目录文件(是目录文件为真) -e 文件 判断该文件是否存在(存在为真) -f 文件 判断该文件是 ...
- canvas常用api
1. 在canvas标签中给出长宽(不带单位):<canvas width="600" height="600"></canvas> 或 ...
- UITableView 之 点击cell 实现两个自定义cell之间的切换
- github上fork了别人的项目后,再同步更新别人的提交
我从github网站和用Git命令两种方式说一下. github网站上操作 打开自己的仓库,进入code下面. 点击new pull request创建. 选择base fork 选择head fo ...
- Mac 系统安装 oh my zsh
先来张图感受一下: 安装oh my zsh: 1.克隆这个项目到本地(前提是你得有装git) git clone git://github.com/robbyrussell/oh-my-zsh.git ...
- Linux-安装FFmpeg
FFmpeg官网:http://www.ffmpeg.org 官网介绍 FFmpeg is the leading multimedia framework, able to decode, enco ...
- Apollo阿波罗配置中心docker
前言 在分布式系统中,要改个配置涉及到很多个系统,一个一个改效率低下,吃力不讨好.用配置中心可以解决这个问题.当然配置中心有不少,以下对比的表格是照搬Apollo Wiki的. 功能点 Apollo ...