原先的连接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. [ERROR]Unable to locate package

    刚更换了DNS,需要更新下apt-get $ apt-get update

  2. 力扣(LeetCode)单值二叉树 个人题解

    如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树. 只有给定的树是单值二叉树时,才返回 true:否则返回 false. 示例 1: 输入:[1,1,1,1,1,null,1] 输出:tr ...

  3. Python 命令行之旅:深入 click 之子命令篇

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  4. PostGIS 递归方法

    在Oracle数据库中,有可以实现递归的函数 select * from table_name start with [condition1] connect by [condition2] 最近发现 ...

  5. 投票通过,PHP 8 确认引入 Union Types 2.0

    关于是否要在 PHP 8 中引入 Union Types 的投票已于近日结束,投票结果显示有 61 名 PHP 开发组成员投了赞成票,5 名投了反对票. 还留意到鸟哥在投票中投了反对票~) 因此根据投 ...

  6. linux 进程简介

    进程相关知识简介 进程定义: 一个运行中的程序即一个process task struct: 内核存储进程信息的固定格式称为task struct,task struct记录了例如该进程内存下一跳位置 ...

  7. css优先级之important

    css优先级之important

  8. JDK1.8新特性(一):stream

    一.什么是stream? 1.概述 Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据. 这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管 ...

  9. python内置的进制转换方法

    python进制转换方法总结表: ↓ 2进制 8进制 10进制 16进制 2进制 - bin(int(x, 8)) bin(int(x, 10)) bin(int(x, 16)) 8进制 oct(in ...

  10. Java集合框架 10 连问,你有被问过吗?

    首先要说一下,本文对这些Java集合框架的面试题只做了一个总结式的回答,对每一道题目,都值得深入去了解一下(什么是扎实基本功,这些就是基本功~~),后续可能对每一道题目拆开独立篇章来深入讲解一下. 大 ...