简明入门教程,参考:https://www.cnblogs.com/CQY1183344265/p/5854418.html
进行此章节之前,介绍一个JdbcUtils的再次的简单封装
(例如后面需要构造QueryRunner时得到数据源等的简便的操作)
package cn.itcast.jdbcutils;import java.sql.Connection;
import java.sql.SQLException;import com.mchange.v2.c3p0.ComboPooledDataSource;public class JdbcUtils {//使用的是默认的配置信息,注意给出c3p0-config.xml配置文件private static ComboPooledDataSource dataSource = new ComboPooledDataSource();//处理多线程的并发访问问题,使用ThreadLocalprivate static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();public static Connection getConnection() throws SQLException{//不为Null说明开启了事务,返回连接//先获取自己线程的ConnectionConnection con = tl.get();if(con != null) return con;return dataSource.getConnection();}/*** 大方一点,给出连接池对象给你*/public static ComboPooledDataSource getDataSource(){return dataSource;}//给出三个方法/*** 开启事务* 创建一个Connection,设置为手动提交* 保证DAO使用的就是这个事务的连接* 同时还需要保证下面两个提交与回滚是同一个连接* 通过创建一个本类的连接成员* @throws SQLException */public static void startTransaction() throws SQLException{Connection con = tl.get();//开启事务后con不再为nullcon = getConnection();con.setAutoCommit(false);//保存连接
tl.set(con);}/*** 提交事务* @throws SQLException */public static void commitTransaction() throws SQLException{Connection con = tl.get();if(con == null) throw new SQLException("事务未开启,请勿提交!");con.commit();con.close();//清空连接con = null;//移除事务
tl.remove();}/*** 回滚事务* @throws SQLException */public static void rollbackTransaction() throws SQLException {Connection con = tl.get();if(con == null) throw new SQLException("事务未开启,请勿回滚!");con.rollback();con.close();con = null;tl.remove();}/*** 用于释放连接* @param connection* @throws SQLException */public static void releaseConnection(Connection connection) throws SQLException{//事务专用则不关闭,后续会有关闭//如果不是事务,则需要关闭Connection con = tl.get();//事务都没有,直接关闭if(con == null) connection.close();//有事务,判断是否相等,是否为专用连接if(con != connection) connection.close();}
}
一、简易的入门:
common-dbutils是Apache对Jdbc的一个简单的封装,其中主要涉及的类有:
QueryRunner
ResultSetHandler
DbUtils
使用的依赖如下:
1.
重要类 QueryRunner (构造时提供数据源)
重要方法:int update(String sql,Object...params);增删改
重载版本 int update(Connection con,String sql,Object...params);本方法不再管理con,由外部提供(保证是同一个)
T query(String sql,ResultSetHandler rsh,Object...params);查询
重载版本类同上
给出一个使用的小例子:
package cn.itcast.demo;import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;import cn.itcast.jdbcutils.JdbcUtils;/*** 测试commons-dbutils* @author jiangbei01**/
public class Demo02 {@Testpublic void testfun1() throws SQLException{QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());String sql = "INSERT INTO ab VALUES(?,?)";Object[] params = {8,"肖恩"};qr.update(sql, params);}
}
2.
给一张表对应一个类,字段与属性对应起来
他会先得到ResultSet,然后调用handler方法转换成需要的类型
接口ResultSetHandler,我们学习的实现类:
BeanHandler 构造器需要一个class参数,返回指定类型的javabean对象 一行记录
BeanListHandler 构造器同上,由名称知为多行,转换成list对象,多个javabean 多行记录
MapHandler 把一行记录转换成一个map (如{name:zhangsan,age:20}) 一行记录
MapListHandler 同上对比,多个map的多行记录,返回List<Map>,返回的也是一个List 多行记录
ScalarHandler 单行单列,通常与select count(*) from stu; 单行单列
这里使用装饰者模式加上开头改造的工具类,将QueryRunner稍加改造
package cn.itcast.jdbcutils;import java.sql.Connection;
import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
/*** 这个类可以自身自己处理连接问题,可以通过jdbcUtils释放连接(类方法会处理是否关闭)* @author jiangbei01**/
public class TxQueryRunner extends QueryRunner {@Overridepublic int[] batch(String sql, Object[][] params) throws SQLException {/** 得到连接* 执行父类方法* 释放连接* 返回值*/Connection con = JdbcUtils.getConnection();int[] results = super.batch(con,sql, params);JdbcUtils.releaseConnection(con);return results;}@Overridepublic <T> T query(String sql, Object param, ResultSetHandler<T> rsh) throws SQLException {/** 得到连接* 执行父类方法* 释放连接* 返回值*/Connection con = JdbcUtils.getConnection();T results = super.query(con,sql, param,rsh);JdbcUtils.releaseConnection(con);return results;}@Overridepublic <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh) throws SQLException {Connection con = JdbcUtils.getConnection();T results = super.query(con,sql, params,rsh);JdbcUtils.releaseConnection(con);return results;}@Overridepublic <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {Connection con = JdbcUtils.getConnection();T results = super.query(con,sql, rsh,params);JdbcUtils.releaseConnection(con);return results;}@Overridepublic <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {Connection con = JdbcUtils.getConnection();T results = super.query(con,sql, rsh);JdbcUtils.releaseConnection(con);return results;}@Overridepublic int update(String sql, Object... params) throws SQLException {Connection con = JdbcUtils.getConnection();int results = super.update(con,sql,params);JdbcUtils.releaseConnection(con);return results;}@Overridepublic int update(String sql, Object param) throws SQLException {Connection con = JdbcUtils.getConnection();int results = super.update(con,sql,param);JdbcUtils.releaseConnection(con);return results;}@Overridepublic int update(String sql) throws SQLException {Connection con = JdbcUtils.getConnection();int results = super.update(con,sql);JdbcUtils.releaseConnection(con);return results;}}
给出一个使用改造类的小例子:
package cn.itcast.jdbcutils;import java.sql.Connection;
import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;public class AccountDAO {/*** 不能使用连接池* 要自己提供连接才能保证是同一个连接* @param name* @param money* @throws SQLException*/public static void update(String name, double money) throws SQLException{QueryRunner qr = new TxQueryRunner();String sql = "update account set balaence=balaence+? where name=?";Object[] params = {money,name};//给出参数并执行
qr.update(sql,params);/** 以下代码新写的Tx类已经完成,无需处理* Connection con = JdbcUtils.getConnection();* //释放连接JdbcUtils.releaseConnection(con);*/}
}
并发访问时产生的问题,可以使用ThreadLocal类(待更新详细)进行解决,示例如下:
package cn.itcast.jdbcutils;import java.sql.Connection;
import java.sql.SQLException;import com.mchange.v2.c3p0.ComboPooledDataSource;public class JdbcUtils {//使用的是默认的配置信息,注意给出c3p0-config.xml配置文件private static ComboPooledDataSource dataSource = new ComboPooledDataSource();//处理多线程的并发访问问题,使用ThreadLocalprivate static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();public static Connection getConnection() throws SQLException{//不为Null说明开启了事务,返回连接//先获取自己线程的ConnectionConnection con = tl.get();if(con != null) return con;return dataSource.getConnection();}/*** 大方一点,给出连接池对象给你*/public static ComboPooledDataSource getDataSource(){return dataSource;}//给出三个方法/*** 开启事务* 创建一个Connection,设置为手动提交* 保证DAO使用的就是这个事务的连接* 同时还需要保证下面两个提交与回滚是同一个连接* 通过创建一个本类的连接成员* @throws SQLException */public static void startTransaction() throws SQLException{Connection con = tl.get();//开启事务后con不再为nullcon = getConnection();con.setAutoCommit(false);//保存连接
tl.set(con);}/*** 提交事务* @throws SQLException */public static void commitTransaction() throws SQLException{Connection con = tl.get();if(con == null) throw new SQLException("事务未开启,请勿提交!");con.commit();con.close();//清空连接con = null;//移除事务
tl.remove();}/*** 回滚事务* @throws SQLException */public static void rollbackTransaction() throws SQLException {Connection con = tl.get();if(con == null) throw new SQLException("事务未开启,请勿回滚!");con.rollback();con.close();con = null;tl.remove();}/*** 用于释放连接* @param connection* @throws SQLException */public static void releaseConnection(Connection connection) throws SQLException{//事务专用则不关闭,后续会有关闭//如果不是事务,则需要关闭Connection con = tl.get();//事务都没有,直接关闭if(con == null) connection.close();//有事务,判断是否相等,是否为专用连接if(con != connection) connection.close();}
}