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>