(一、DBUtil工具类)
package com.aishang.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DbUtil {
private static String url = "jdbc:mysql://localhost:3306/day11";
private static String name = "root";
private static String password = "root";
private static Connection conn;
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//从数据库中获取连接
public static Connection getConnection() {
try {
conn = DriverManager.getConnection(url, name, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
//将连接关闭
public static void close(Connection conn, PreparedStatement ps, ResultSet rs) {
try {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(二、DBCPUtil工具类)
package com.aishang.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class DBCPUtil {
private static DataSource ds = null;
//连接驱动
static{
Properties prop = new Properties();
try {
prop.load(DBCPUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"));
ds = BasicDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
throw new ExceptionInInitializerError("初始化错误,请检查配置文件");
}
}
//从数据库中获得连接
public static Connection getConnection(){
try {
return ds.getConnection();
} catch (SQLException e) {
throw new RuntimeException("服务器忙。。。");
}
}
//将连接关闭
public static void close(Connection conn, PreparedStatement ps, ResultSet rs) {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
ps = null;
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
(三、ThreadLocal工具类)
package com.aishang.util;
import java.sql.Connection;
import java.sql.SQLException;
public class ManageThreadLocal {
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
//将Connection对象保存到线程对象中
public static Connection getConnection(){
Connection conn = tl.get();
if(conn==null){
conn = DBCPUtil.getConnection();
tl.set(conn);
}
return conn;
}
//设置事务为手动提交
public static void setAutoCommit(){
try {
getConnection().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
//提交事务
public static void commit(){
try {
getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
//回滚事务
public static void rollback(){
try {
getConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
//将conn还回池子,并将对象与线程解绑
public static void close(){
try {
getConnection().close();
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
相比于前面的两种方式,ThreadLocal的优点在于:事物的操作
事务操作,需要将不同的子业务放到同一个Connection,事务是依赖于Connection的业务操作,需要将不同的子业务放到同一个Connection,事务是依赖于Connection的。
解决方式I:Dao层,需要注入进来类级别的成员变量Connection,保证,查询和修改方法都是用的是同一Connection对象。问题得以解决,但是产生一个很大的问题:Connection对象不应该出现在service层,应该出现在dao层的代码出现在了service层,但是为了保证传入dao层的Connection是一个,并且保证事务操作,没有办法只能出现在service层,因此这不是一个好的解决方案。
解决方式II:增加ThreadLocal工具类
ThreadLocal介绍
代码模拟:
思路:不同的用户访问服务器,要开启不同的线程,如果让当前某一个线程,操作同一个Connection对象,可以保证Service层以及两次调用dao层完成账户修改的功能,使用的都是一个Connection对象,即:与当前线程绑定的Connection对象,这就具备了事务操作的基础(同一个Connection对象)。怎样让当前的线程记录并绑定同一个Connection对象?使用Java内置好的ThreadLocal类(封装了一种结构,并提供操作方法)
public int addNews(News news){
int res = 0;
int id = -1;
try {
/*conn = DBCPUtil.getConnection();过去的写法,不能保证事务中对Connection一致的要求*/
String sql = "insert into tb_news values(default,?,?,?,?,?,?)";
ps = ManageThreadLocal.getConnection().prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);//为事务获得统一Connection对象
ps.setString(1, news.getTitle());
ps.setString(2, news.getContent());
ps.setInt(3,news.getTypeId());
ps.setInt(4, news.getFlag());
ps.setString(5, news.getCreateTime());
ps.setInt(6, news.getUserId());
ps.executeUpdate();
rs=ps.getGeneratedKeys();//这一句代码就是得到插入的记录的id
while(rs.next()){
id=rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
DBCPUtil.close(null, ps, rs);//关闭时不可以关闭统一的conn对象,开着供其他人使用
}
return id;//添加新闻文本后需要立刻获得刚添加的新闻的id,为新闻图片添加得到最新nid
}