JDBC补充:DBUtils和ThreadLocal
来源:互联网 发布:新手开淘宝店教程 编辑:程序博客网 时间:2024/06/11 04:13
- DBUtils
- ThreadLocal
- DBUtils与ThreadLocal合并运用
DBUtils
- 导包
commons-dbutils-xxx.jar包和commons-pool-xxx.jar包,xxx是版本号。 使用
package com.jyh.dbutil;import java.sql.SQLException;import java.util.Date;import java.util.List;import java.util.Map;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.ArrayHandler;import org.apache.commons.dbutils.handlers.ArrayListHandler;import org.apache.commons.dbutils.handlers.BeanHandler;import org.apache.commons.dbutils.handlers.BeanListHandler;import org.apache.commons.dbutils.handlers.ColumnListHandler;import org.apache.commons.dbutils.handlers.KeyedHandler;import org.apache.commons.dbutils.handlers.MapHandler;import org.apache.commons.dbutils.handlers.MapListHandler;import org.apache.commons.dbutils.handlers.ScalarHandler;import org.junit.Test;import com.jyh.domain.User;import com.jyh.jdbc.DBCPUtil;/** * dbutils框架的使用 * @author OverrideRe * */public class DBUtilDemo { /** * 传入数据源代表不需要事务,不传代表需要事务 *传入数据源说明是从数据源随机获取链接,不一定是同一个链接,所以没法进行事务操作 *如果需要进行事务操作需要同一个链接 */ private QueryRunner qr = new QueryRunner(DBCPUtil.getDataSource()); //没有返回值的增删改等 @Test public void test1() throws SQLException{ qr.update("insert into user(name,password,email,birthday) values(?,?,?,?)", "大狗","123","dagou@qq.com","1994-01-01"); } //批处理 @Test public void test2() throws SQLException{ Object[][] params = new Object [10][]; for(int i = 0;i < 10;i ++){ params[i] = new Object[]{"a"+i,"123","a"+i+"@qq.com",new Date()}; } qr.batch("insert into user(name,password,email,birthday) values(?,?,?,?)", params); } //ArrayHandler:有一条返回结果的查询语句,查询结果封装到一个Object[]中去 @Test public void test3() throws SQLException{ Object[] objs = qr.query("select * from user", new ArrayHandler()); for(Object obj : objs) System.out.println(obj); } //ArrayListHandler:有多条返回结果的查询语句,查询结果先将每条封装到一个Object[]中去,再封装到list中去 @Test public void test4() throws SQLException{ List<Object[]> list = qr.query("select * from user", new ArrayListHandler()); for (Object[] objects : list) { for (Object object : objects) { System.out.print(object + "---"); } System.out.println(); } } //ColumnListHandler:封装某列的值,将某一列的值封装进list中去 @Test public void test5() throws SQLException{ //ColumnListHandler有两种构造方法,一种是传列的序号,一种是传列名 List<Object> list = qr.query("select * from user", new ColumnListHandler("name")); for (Object object : list) { System.out.print(object + "---"); } System.out.println(); } /**KeyedHandler:以键值对形式封装数据,每条记录封装进键值对集合,value为各属性值,key为各属性值对应的属性名 *然后再将每条记录封装进键值集合,key值自己定(一般为id),value值就是每条记录,也就是刚刚封装的键值对集合 *意思就是双重map */ @Test public void test6() throws SQLException{ Map<Object, Map<String, Object>> keyMap = qr.query("select * from user", new KeyedHandler("id")); for (Map.Entry<Object, Map<String, Object>> enMap : keyMap.entrySet()) { System.out.print("key:" + enMap.getKey()); for (Map.Entry<String, Object> en: enMap.getValue().entrySet()) { System.out.print("---" + en.getKey() + ":" + en.getValue()); } System.out.println(); } System.out.println(); } //MapHandler:取一条数据,将列名和所对应的值以键值对形式封装 @Test public void test7() throws SQLException{ Map<String, Object> keyMap = qr.query("select * from user", new MapHandler()); for (Map.Entry<String, Object> en : keyMap.entrySet()) { System.out.println(en.getKey() + ":" + en.getValue()); } System.out.println(); } //MapListHandler:取多条数据,将列名和所对应的值以键值对形式封装进map集合,然后再将map集合装进list中去 //与KeyedHandler不同的是,每一条数据是装在List中而不是Map键值对集合中 @Test public void test8() throws SQLException{ List<Map<String, Object>> keyList = qr.query("select * from user", new MapListHandler()); for (Map<String, Object> enMap : keyList) { for (Map.Entry<String, Object> en: enMap.entrySet()) { System.out.print("---" + en.getKey() + ":" + en.getValue()); } System.out.println(); } System.out.println(); } //ScalarHandler:返回某行某列的一个数据,如查询总数coutn(*) @Test public void test9() throws SQLException{ Object l= qr.query("select * from user", new ScalarHandler()); System.out.println(l); } //BeanHandler:将一条数据封装进某个bean类中去 @Test public void test10() throws SQLException{ User l= qr.query("select * from user", new BeanHandler<User>(User.class)); System.out.println(l.getName()); } //BeanListHandler:获取多条数据,将每条数据封装进bean中然后再添加进集合中去 @Test public void test11() throws SQLException{ List<User> l= qr.query("select * from user", new BeanListHandler<User>(User.class)); System.out.println(l.get(0).getName()); }}
ThreadLocal
ThreadLocal为线程局部变量,看着名字就知道是保存在线程上的变量
1. 声明实例:ThreadLocal<T> tl = new ThreadLocal<T>();
T为要保存的数据类型。
2. 常用方法:set(T t),get(),remove()。
3. 作用:将数据保存在当前线程中,为线程私有,利用线程之间的互相隔离,保证
变量只能在当前线程中被改变。普通的变量就是保存在外面,任何线程都可以访问,所以每个线程访问的数据都可能是经过别的线程改变之后的数据。
4. 实现原理:查看源码。
为了文章的长度,把源码加上:
set(T value)方法:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
set方法中调用的getMap(Thread t)方法
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
set方法中调用的creatMap(Thread t, T firstValue)方法:
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
Thread类中的threadLocals 参数:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
查看以上代码可知,set方法是将要保存的数据作为value,当前ThreadLocal实例作为key值保存在当前线程中的一个map中,这个map类是ThreadLocal.ThreadLocalMap,是ThreadLocal的内部类。
做个小实验:
ThreadLocal<Integer> iLocal = new ThreadLocal<Integer>();iLocal.set(1);iLocal.set(2);ThreadLocal<String> sLocal = new ThreadLocal<String>();sLocal.set("a");sLocal.set("b");System.out.println(iLocal.get());System.out.println(sLocal.get());
输出结果是2,b。也可以看看这篇博客:
http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/
DBUtils与ThreadLocal合并运用
刚刚说了要使用事务就必须保证链接是同一个,所以可以利用ThreadLocal来实现。
一个转账小例子:
开始转账:
package com.jyh.test;import com.jyh.service.AccountService;import com.jyh.service.impl.AccountServiceImpl2;import com.jyh.utils.ServiceFactory;public class test { public static void main(String[] args) { AccountService as2 = null; try { //从工厂里面获取实例,第一个参数为true说明是需要事务的 as2 = ServiceFactory.getService(true, AccountServiceImpl2.class); } catch (Exception e) { e.printStackTrace(); } //ccc转账100给aaa as2.transfer("ccc", "aaa", 100); }}
工厂类:
package com.jyh.utils;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 工厂模式来决定service如何实现 * @author OverrideRe * */public class ServiceFactory { public static <T> T getService(boolean isProxy,Class<T> clazz) throws Exception{ final T t = clazz.newInstance(); if(isProxy){//如果是true说明需要事务,那么对每个方法的调用都要用事务包起来 //代理模式监视每个方法 @SuppressWarnings("unchecked") T tt = (T)Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("工厂模式里的代理模式"); try { //方法执行前开启事务 ThreadLocalUtil.startTransaction(); //方法执行 method.invoke(t, args); //方法执行之后提交事务 ThreadLocalUtil.commit(); } catch (Exception e) { //回滚事务 ThreadLocalUtil.rollBack(); throw new RuntimeException(e); }finally{ //释放资源 ThreadLocalUtil.release(); } return null; } }); return tt; } return t; }}
获取链接的ThreadLocalUtil工具类:
package com.jyh.utils;import java.sql.Connection;import java.sql.SQLException;@SuppressWarnings("rawtypes")public class ThreadLocalUtil extends ThreadLocal{ private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); public static Connection getConnection(){ Connection conn = tl.get();//获取线程中保存的链接 if(conn == null){//如果没有则创建一个链接set进去 conn = DBCPUtil.getConnection(); tl.set(conn); } return conn; } //开启事务 public static void startTransaction(){ Connection conn = getConnection(); try { conn.setAutoCommit(false); } catch (SQLException e) { e.printStackTrace(); } } //提交事务 public static void commit(){ Connection conn = getConnection(); try { conn.commit(); } catch (SQLException e) { e.printStackTrace(); } } //回滚事务 public static void rollBack(){ Connection conn = getConnection(); try { conn.rollback(); } catch (SQLException e) { e.printStackTrace(); } } //释放资源 public static void release(){ Connection conn = getConnection(); try { conn.close(); tl.remove();//移除 } catch (SQLException e) { e.printStackTrace(); } }}
业务逻辑类:
package com.jyh.service.impl;import com.jyh.dao.AccountDao;import com.jyh.dao.impl.AccountDaoImpl;import com.jyh.domain.Account;import com.jyh.service.AccountService;public class AccountServiceImpl2 implements AccountService { private AccountDao ad = new AccountDaoImpl(); //实现用户转账 public void transfer(String sourceName, String targetName, Integer money) { Account a = ad.query(sourceName);//获取a用户 Account b= ad.query(targetName);//获取b用户 a.setSalary(a.getSalary() - money);//a用户减少这么多money b.setSalary(b.getSalary() + money);//b用户增加这么多money //更新数据库 ad.update(a); ad.update(b); }}
dao实现类:
package com.jyh.dao.impl;import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanHandler;import com.jyh.dao.AccountDao;import com.jyh.domain.Account;import com.jyh.utils.ThreadLocalUtil;public class AccountDaoImpl implements AccountDao { //这里没有传递数据源 private QueryRunner qr = new QueryRunner(); public AccountDaoImpl(){ } public void update(Account account) { try { //这里传递了一个链接,为了实现事务 qr.update(ThreadLocalUtil.getConnection(),"update account set salary = ? where id = ?", account.getSalary(),account.getId()); } catch (SQLException e) { e.printStackTrace(); } } public Account query(String name) { try { return qr.query(ThreadLocalUtil.getConnection(), "select * from account where name = ?", new BeanHandler<Account>(Account.class),name); } catch (SQLException e) { throw new RuntimeException(e); } }}
- JDBC补充:DBUtils和ThreadLocal
- javaEE(DBUtils和ThreadLocal)
- JDBC框架 和 Apache—DBUtils框架
- JDBC元数据和DbUtils框架
- JDBC连接和DBUtils的使用详解
- JDBC学习06-DBUtils下载和使用
- jdbc事务封装之DBCPUtil和ThreadLocal
- mysql数据库中JDBC与DBUtils的笔记和总结
- DbUtils简单封装JDBC
- JDBC-DBUtils工具类
- JDBC之DbUtils工具
- JDBC工具-DBUtils
- JDBC连接池&DBUtils
- JDBC连接池&DBUtils
- QueryRunner(DBUtils工具类)体现了:DBUtils封装了C3P0和jdbc。【三者的关系】
- JDBC之事务的封装和Threadlocal实例
- DbUtils: JDBC Utility Component Examples
- DbUtils: JDBC Utility Component Examples
- 【MFC】UpData()函数更新控件中的内容
- linux挂载报错mount: unknown filesystem type 'LVM2_member'
- 2016年终总结
- 项目制作随感(整理版)
- js标签全选全部选反选
- JDBC补充:DBUtils和ThreadLocal
- 关于ROC AUC指标的详细介绍说明
- SQL Server日志文件过大 大日志文件清理方法 不分离数据库
- webService学习(三)—— 部署webService到tomcat上
- Webpack-dev-server结合后端服务器的热替换配置
- oauth2.0认证和授权原理
- 外观模式(Facade)
- JQuery选择器(四)表单选择器
- 在Linux环境下mysql的root密码忘记解决方法