原先的连接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层,一个用户,一个事务的更多相关文章

  1. spring事务到底用于service层还是dao层

    Spring事务为业务逻辑进行事务管理,保证业务逻辑上数据的原子性. 事务得根据项目性质来细分:事务可以设置到三个层面(dao层.service层和web层). 第一:web层事务,这一般是针对那些安 ...

  2. MVC引入SERVICE层 提高代码重用性 沟通CONTROL和MODEL

    MVC是web开发中常见的程序结构. 简单的mvc结构如下: view层:显示层. control层:业务层,集合了各种action. model层:模型层,一般和数据打交道.简单的sample:一个 ...

  3. 032医疗项目-模块三:药品供应商目录模块——供货商药品目录查询功能----------Service层和Action层和调试

    我们上一篇文章讲了Dao层代码: 这一篇我们讲解Service层和Action层: Service层: 分为接口和实现类,我们主要看实现类:GysemplServiceImpl package yyc ...

  4. SSM实战——秒杀系统之Service层接口设计与实现、Spring托管、声明式事务

    一:Service层接口设计 准备工作:新建三个包:service包.exception包.dto包,分别用来存放业务接口.自定义异常类.dto类. 1:定义接口 package org.myseck ...

  5. 【spring data jpa】使用spring data jpa时,关于service层一个方法中进行【删除】和【插入】两种操作在同一个事务内处理

    场景: 现在有这么一个情况,就是在service中提供的一个方法是先将符合条件的数据全部删除,然后再将新的条件全部插入数据库中 这个场景需要保证service中执行两步 1.删除 2.插入 这两步自然 ...

  6. 【mybatis】service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据【事务的问题】

    问题描述: service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据 ...

  7. iBatis——自动生成DAO层接口提供操作函数(详解)

    iBatis——自动生成DAO层接口提供操作函数(详解) 在使用iBatis进行持久层管理时,发现在使用DAO层的updateByPrimaryKey.updateByPrimaryKeySelect ...

  8. UDP 一个封锁操作被对 WSACancelBlockingCall 的调用中断

    using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using S ...

  9. [Socket网络编程]一个封锁操作被对 WSACancelBlockingCall 的调用中断。

    原文地址:http://www.cnblogs.com/xiwang/archive/2012/10/25/2740114.html记录在此,方便查阅. C#中在使用UDPClient循环监听端口,在 ...

随机推荐

  1. OTA升级详解(三)

    君子知夫不全不粹之不足以为美也, 故诵数以贯之, 思索以通之, 为其人以处之, 除其害者以持养之: 出自荀子<劝学篇> 终于OTA的升级过程的详解来了,之前的两篇文章OTA升级详解(一)与 ...

  2. 决策树(上)-ID3、C4.5、CART

    参考资料(要是对于本文的理解不够透彻,必须将以下博客认知阅读,方可全面了解决策树): 1.https://zhuanlan.zhihu.com/p/85731206 2.https://zhuanla ...

  3. 【Linux系列】Centos 7安装以及网络配置(一)

    目的 本文主要介绍以下两点: 一. 如何在Oracle VM VirtualBox安装centos(已有VirtualBox) 二. 如何在内网里实现虚拟机访问外网.物理主机以及物理主机访问虚拟机 一 ...

  4. linux redhat系列后缀为el5,el6,el7软件包的区别

    - EL6软件包用于在Red Hat 6.x, CentOS 6.x, and CloudLinux 6.x进行安装 - EL5软件包用于在Red Hat 5.x, CentOS 5.x, Cloud ...

  5. 怎样在PaaS平台上搭建一个会自动关闭的会议室

    首相得解释一下,什么叫做会自动关闭的会议室.我们的会议室是存在一个会议预定系统的,一般情况下,我们需要开会的时候,需要先抢占会议室.等待要开会的时候,去会议室里边开会,如果里边有别人,我们可以告诉他们 ...

  6. PHP laravel+thrift+swoole打造微服务框架

    Laravel作为最受欢迎的php web框架一直广受广大互联网公司的喜爱. 笔者也参与过一些由laravel开发的项目.虽然laravel的性能广受诟病但是业界也有一些比较好的解决方案,比如堆机器, ...

  7. hdu 1028 Sample Ignatius and the Princess III (母函数)

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  8. ArcGIS API For Javascript :如何制作地图切换器

    大部分情况下我们开发会使用原生的地图切换器,由于每个项目的页面风格不同,业务场景不同,因此需要做一些样式不同的地图切换器. 首先可以照猫画虎,自己照着地图切换器的样式抄一个,或者看看主流的地图切换器都 ...

  9. python:正则0

    Python3 正则表达式特殊符号及用法(详细列表) 正则表达式的强大之处在于特殊符号的应用,特殊符号定义了字符集合.子组匹配.模式重复次数.正是这些特殊符号使得一个正则表达式可以匹配字符串集合而不只 ...

  10. django post请求

    django中提交post请求时候,需要携带CSRF,否则会报403错误,此时需要在form中添加{% csrf_token %} 或者注释掉settings.py -> MIDDLEWARE ...