Filter和 ThreadLocal组合管理事务
Filter和 ThreadLocal组合管理事务
注意!一定要把MySQL的引擎改成InnoDB,只有InnoDB支持事务。创建数据表的时候数据库引擎默认用的是MyISAM不支持事务。
修改my.ini中的default-storage-engine=INNODB
在未修改引擎前创建的表也需要修改引擎设置
alter table table_name engine=innodb;
使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成
JdbcUtils 工具类的修改
public class JdbcUtils {
private static DruidDataSource dataSource;
private static ThreadLocal<Connection> conn = new ThreadLocal<Connection>();
static {
Properties properties = new Properties();
//读取配置文件
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
//从流中加载数据
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
try {
//创建数据库连接池
dataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*获取数据库连接池的链接
* 返回null说明获取连接失败
*/
public static Connection getConnection(){
Connection connection = conn.get();
if(connection==null){
try {
connection = dataSource.getConnection();//从数据库连接池获取连接
conn.set(connection);//保存到threadlocal对象中,供后面的jdbc操作使用
connection.setAutoCommit(false);//设置为手动管理事务
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
public static void rollBackAndClose() {
Connection connection = conn.get();
if(connection!=null){
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public static void commitAndClose() {
Connection connection = conn.get();
if(connection!=null){
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 一定要执行remove 操作,否则就会出错。(因为Tomcat 服务器底层使用了线程池技术)
conn.remove();
}
}
修改 BaseDao
public abstract class BaseDao<T> {
//使用DbUtils操作数据库
private QueryRunner queryRunner = new QueryRunner();
private Class<T> type;
// 获取T的Class对象,获取泛型的类型,泛型是在被子类继承时才确定
public BaseDao() {
// 获取子类的类型
Class clazz = this.getClass();
// 获取父类的类型
// getGenericSuperclass()用来获取当前类的父类的类型
// ParameterizedType表示的是带泛型的类型
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
// 获取具体的泛型类型 getActualTypeArguments获取具体的泛型的类型
// 这个方法会返回一个Type的数组
Type[] types = parameterizedType.getActualTypeArguments();
// 获取具体的泛型的类型·
this.type = (Class<T>) types[0];
}
/**
* 执行insert update delete
* 返回-1说明执行失败
* 返回其他表示影响的行数
* @param sql sql语句
* @param args 参数
* @return
*/
public int update(String sql,Object ... args){
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.update(connection, sql, args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
*查询返回一个javaBean对象的sql语句
* @param sql sql语句
* @param args sql参数
* @return
*/
public T queryForOne(String sql,Object ...args){
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.query(connection, sql, new BeanHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
*查询返回多个javaBean对象的sql语句
* @param sql sql语句
* @param args sql语句参数
* @return
*/
public List<T> queryForList(String sql, Object ...args){
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.query(connection, sql, new BeanListHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 返回执行一行一列的sql语句
* @param sql sql语句
* @param args sql对应的参数值
* @return
*/
public Object queryForSingleValue(String sql,Object ...args){
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.query(connection, sql, new ScalarHandler(), args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
使用Filter过滤器统一给所有的Service方法都加上try-catch来进行管理
将所有异常都统一交给Tomcat,让Tomcat展示友好的错误信息页面。
在 web.xml 中我们可以通过错误页面配置来进行管理。
<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page>
<!--error-code 是错误类型-->
<error-code>500</error-code>
<!--location 标签表示。要跳转去的页面路径-->
<location>/pages/error/error500.jsp</location>
</error-page>
<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page>
<!--error-code 是错误类型-->
<error-code>404</error-code>
<!--location 标签表示。要跳转去的页面路径-->
<location>/pages/error/error404.jsp</location>
</error-page>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现