对于在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循环监听端口,在 ...
随机推荐
- [ERROR]Unable to locate package
刚更换了DNS,需要更新下apt-get $ apt-get update
- 力扣(LeetCode)单值二叉树 个人题解
如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树. 只有给定的树是单值二叉树时,才返回 true:否则返回 false. 示例 1: 输入:[1,1,1,1,1,null,1] 输出:tr ...
- Python 命令行之旅:深入 click 之子命令篇
作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...
- PostGIS 递归方法
在Oracle数据库中,有可以实现递归的函数 select * from table_name start with [condition1] connect by [condition2] 最近发现 ...
- 投票通过,PHP 8 确认引入 Union Types 2.0
关于是否要在 PHP 8 中引入 Union Types 的投票已于近日结束,投票结果显示有 61 名 PHP 开发组成员投了赞成票,5 名投了反对票. 还留意到鸟哥在投票中投了反对票~) 因此根据投 ...
- linux 进程简介
进程相关知识简介 进程定义: 一个运行中的程序即一个process task struct: 内核存储进程信息的固定格式称为task struct,task struct记录了例如该进程内存下一跳位置 ...
- css优先级之important
css优先级之important
- JDK1.8新特性(一):stream
一.什么是stream? 1.概述 Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据. 这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管 ...
- python内置的进制转换方法
python进制转换方法总结表: ↓ 2进制 8进制 10进制 16进制 2进制 - bin(int(x, 8)) bin(int(x, 10)) bin(int(x, 16)) 8进制 oct(in ...
- Java集合框架 10 连问,你有被问过吗?
首先要说一下,本文对这些Java集合框架的面试题只做了一个总结式的回答,对每一道题目,都值得深入去了解一下(什么是扎实基本功,这些就是基本功~~),后续可能对每一道题目拆开独立篇章来深入讲解一下. 大 ...