Filter和 ThreadLocal组合管理事务

Filter和 ThreadLocal组合管理事务

注意!一定要把MySQL的引擎改成InnoDB,只有InnoDB支持事务。创建数据表的时候数据库引擎默认用的是MyISAM不支持事务。

修改my.ini中的default-storage-engine=INNODB

在未修改引擎前创建的表也需要修改引擎设置

alter table table_name engine=innodb;

使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成

Filter和 ThreadLocal组合管理事务

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来进行管理

Filter和 ThreadLocal组合管理事务

将所有异常都统一交给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>
上一篇:Linux iptables的使用(自打版)


下一篇:使用python提供HTTPS服务