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);
}
}
}