对于在Dao层,一个DML操作一个事务,升级到Service层,一个用户,一个事务
原先的连接Connection,只能是来一次,新创建一个连接connection。这样如果事务在Dao层已经默认提交,在service层出错时,对于俩张关联会有俩种不同的结果。为了解决这样的问题,我们将事务提升到service层。用到 threadlocation。
package com.bjsxt.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DBUtil2 {
static String driver;
static String url;
static String user;
static String password;
//定义一个threadLocal变量,存放collection,可以保证在同于个线程中,多个不同层次,不同方法,都是用的是同一个collection。
private static ThreadLocal<Connection> threadLocal=new ThreadLocal<Connection>();
//读取属性文件properties并获取内容
static{
//准备一个空的map,没有key-value
Properties prop = new Properties();
//读取文件,并将文件键值对存入Properties对象
//InputStream is = new FileInputStream(new File("C:\Users\Administrator\workspace\java_empmgr2\src\conn.properties"));
InputStream is = DBUtil2.class.getResourceAsStream("/jdbc.properties"); //classpath
try {
prop.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//从prop中根据key获取四个参数的值
driver = prop.getProperty("driver");
//driver = prop.get("driver");
url = prop.getProperty("url");
user = prop.getProperty("username");
password = prop.getProperty("password");
//加载驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接
* @return
*/
public static Connection getConnection(){
Connection conn = null;
//不是直接创建新的连接,而是次用threadLocal中获取
conn = threadLocal.get();
if (conn==null) {
//当前线程第一次获取连接,需要建立数据库的连接
try{
//建立数据库连接
conn = DriverManager.getConnection(url, user, password);
}catch(SQLException e){
e.printStackTrace();
}
//再放入threadlocal
threadLocal.set(conn);
}
return conn;
}
/**
* 关闭数据库资源
* @param rs
* @param stmt
* @param conn
*/
public static void closeAll(ResultSet rs ,Statement stmt,Connection conn){
//关闭数据库资源
try {
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(stmt != null){
stmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn != null){
threadLocal.set(null);//将conn从threadLocal中移除
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* DML:insert update delete
*/
public static int executeUpdate(String sql,Object ... params) {
Connection conn = null;
PreparedStatement pstmt = null;
int n = 0;
try{
//获取数据库连接
conn = DBUtil2.getConnection();
//使用手枪发送SQL命令并得到结果
pstmt = conn.prepareStatement(sql);
for(int i=0;i<params.length;i++){
pstmt.setObject(i+1, params[i]);
}
n = pstmt.executeUpdate();
}catch(SQLException e){
//处理异常
e.printStackTrace();
//throw e;
//抛出异常给上级(调用者)
//throw new RuntimeException(e.toString());
throw new MyException(e.toString());
}finally{
//关闭数据库资源
DBUtil2.closeAll(null, pstmt, null);//采用业务层事务后,dao层不关闭连接
}
//返回数据
return n;
}
public static void main(String[] args) {
Connection conn = getConnection();
System.out.println(conn);
}
}
比原先的工具类不同的是。用到 DBUtil2时,我们将关闭connection都放在service层统一关闭。
public void add(Expense expense) {
//获取序列的下一个值,
ExpenseDao expDao = new ExpenseDaoImpl();
int expId = expDao.nextVal();
//开启手动提交事务
Connection conn=DBUtil2.getConnection();
try {
//将自动提交事务关闭(此时并没有事务提交)
conn.setAutoCommit(false);
//添加一条报销单(主单)信息
expense.setExpId(expId);
expDao.save(expense);
//添加多条报销单所属的明细的信息
ExpenseItemDao itemDao = new ExpenseItemDaoImpl();
List<ExpenseItem> itemList = expense.getItemList();
for(int i=0;i<itemList.size();i++){
ExpenseItem item = itemList.get(i);
item.setExpId(expId);
itemDao.save(item);
}
//结束事务(提交或者回滚)
conn.commit();//提交事务
} catch (Exception e) {
try {
//回滚事务
conn.rollback();//会清空缓存
} catch (SQLException e1) {
e1.printStackTrace();
throw new MyException(e1.toString());
}
throw new MyException(e.toString());
}
finally{
DBUtil2.closeAll(null, null, conn);
}
}
对于在Dao层,一个DML操作一个事务,升级到Service层,一个用户,一个事务的更多相关文章
- spring事务到底用于service层还是dao层
Spring事务为业务逻辑进行事务管理,保证业务逻辑上数据的原子性. 事务得根据项目性质来细分:事务可以设置到三个层面(dao层.service层和web层). 第一:web层事务,这一般是针对那些安 ...
- MVC引入SERVICE层 提高代码重用性 沟通CONTROL和MODEL
MVC是web开发中常见的程序结构. 简单的mvc结构如下: view层:显示层. control层:业务层,集合了各种action. model层:模型层,一般和数据打交道.简单的sample:一个 ...
- 032医疗项目-模块三:药品供应商目录模块——供货商药品目录查询功能----------Service层和Action层和调试
我们上一篇文章讲了Dao层代码: 这一篇我们讲解Service层和Action层: Service层: 分为接口和实现类,我们主要看实现类:GysemplServiceImpl package yyc ...
- SSM实战——秒杀系统之Service层接口设计与实现、Spring托管、声明式事务
一:Service层接口设计 准备工作:新建三个包:service包.exception包.dto包,分别用来存放业务接口.自定义异常类.dto类. 1:定义接口 package org.myseck ...
- 【spring data jpa】使用spring data jpa时,关于service层一个方法中进行【删除】和【插入】两种操作在同一个事务内处理
场景: 现在有这么一个情况,就是在service中提供的一个方法是先将符合条件的数据全部删除,然后再将新的条件全部插入数据库中 这个场景需要保证service中执行两步 1.删除 2.插入 这两步自然 ...
- 【mybatis】service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据【事务的问题】
问题描述: service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据 ...
- iBatis——自动生成DAO层接口提供操作函数(详解)
iBatis——自动生成DAO层接口提供操作函数(详解) 在使用iBatis进行持久层管理时,发现在使用DAO层的updateByPrimaryKey.updateByPrimaryKeySelect ...
- UDP 一个封锁操作被对 WSACancelBlockingCall 的调用中断
using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using S ...
- [Socket网络编程]一个封锁操作被对 WSACancelBlockingCall 的调用中断。
原文地址:http://www.cnblogs.com/xiwang/archive/2012/10/25/2740114.html记录在此,方便查阅. C#中在使用UDPClient循环监听端口,在 ...
随机推荐
- 瞎折腾实录:构建 Armel 版本的 .NET Core 教程和资料资源
目录 首先我要说明,我失败了~ 我把我的进度和经验放出来,希望能够帮助别人完成编译工作~ 背景:最近接手一个华为某型号的嵌入式设备,需要在上面搭建 .NET Core 环境. 设备是 Armel 架构 ...
- Ansible之常用模块(二)
1.hostname:此模块的主要作用是管理远端节点主机名 模块帮助: root@localhost ~]# ansible-doc -s hostname - name: Manage hostna ...
- 深入理解计算机系统 第二章 信息的表示和处理 Part2 第二遍
<深入理解计算机系统> 第三版 第二遍读这本书,每周花两到三小时时间,能读多少读多少(这次看了 29 ~ 34 页) 第一遍对应笔记链接 https://www.cnblogs.com/s ...
- windows 2008 服务器优化:停powershell,卸载不相干软件,开启防火墙
windows 2008 作为 全录 的服务器,经常cpu达到100%,查看是powershell.exe占cpu有98%.影响 全录 软件进行电话录音.所以想禁止powershell.exe程序启动 ...
- C++中对C的扩展学习新增语法——内联函数以及函数参数
内联函数以及函数参数 内联函数 使用 inline 关键字必须和函数体放在一起. 内联函数具有内部链接属性. 内联函数会被编译器在编译阶段替换到函数调用的地方. 可以把内联函数定义写到头文件中,多个c ...
- Linux下编写-makefile-详细教程(跟我一起写-Makefile-Markdown整理版)
目录 概述 关于程序的编译和链接 Makefile 介绍 Makefile的规则 一个演示例子 make是怎样工作的 makefile中使用变量 让make自己主动推导 另类风格的makefile 清 ...
- [LC]141题 Intersection of Two Linked Lists (相交链表)(链表)
①中文题目 编写一个程序,找到两个单链表相交的起始节点. 如下面的两个链表: 在节点 c1 开始相交. 注意: 如果两个链表没有交点,返回 null.在返回结果后,两个链表仍须保持原有的结构.可假定整 ...
- jeson navo
QT TEMPLATE = app CONFIG += console c++11 CONFIG -= app_bundle CONFIG -= qt INCLUDEPATH += /usr/loca ...
- Error: Cannot find module 'less'
这是webpack.config 代码中引入 报错信息(在main.js中引入也是这个报错 解决办法: 安装less: npm install less --save-dev 转自: https:// ...
- 稀疏数组 python描述
什么是稀疏矩阵? 在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵. 作用: 在这种情况下,很多0值无疑是很浪费空间的,当我们要把数组存储在磁盘中 ...