首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > 其他数据库 >

JDBC-自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表

2013-07-11 
JDBC--自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表本文查阅方法:??? 1、查阅目录 —— 查阅本文目

JDBC--自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表

本文查阅方法:
??? 1、查阅目录 —— 查阅本文目录,确定想要查阅的目录标题
??? 2、快捷“查找” —— 在当前浏览器页面,按键 “Ctrl+F” 按键组合,开启浏览器的查找功能,
???????????? 在查找搜索框中 输入需要查阅的 目录标题,便可以直接到达 标题内容 的位置。
??? 3、学习小结 —— 文中的学习小结内容,是笔者在学习之后总结出的,开发时可直接参考其进行应用开发的内容, 进一步加快了本文的查阅 速度。(水平有限,仅供参考。)
?

?

?

?

?

本文目录

?

??????学习小结

?

??????1、自定义JDBC框架?——数据库元数据:DataBaseMetaData

?

??????2、自定义JDBC框架?——数据库元数据:DataBaseMetaData

?

??????3、自定义JDBC框架?——结果集元数据:?ResultSetMetaData

?

??????4、使用元数据简化JDBC代码

?

????????????(1)?万能更新

?

????????????(2)?万能查询

?

??????5、Apache—DBUtils框架简介

?

??????6、DbUtils类?介绍

?

??????7、QueryRunner类?介绍

?

??????8、QueryRunner类的主要方法

?

??????9、ResultSetHandler接口?介绍

?

??????10、ResultSetHandler?接口的实现类

?

??????11、JDBC应用的事务管理(ThreadLocal类)?

?

??????12、JDBC应用的事务管理——采用跨层跨层传递方法参数

?

??????13、JDBC应用的事务管理——?ThreadLocal?绑定连接

?

??????14、使用JDBC操作多个表

?

??????15、使用JDBC操作多个表——?“一对多”关系?

?

??????16、使用JDBC操作多个表——?多对多关系

?

??????17、数据库端——表关系间的级联操作

?

?

?

相关学习

?

JDBC?学习笔记(一)——?基础知识?+?分页技术

??????链接地址:http://even2012.iteye.com/blog/1886946

?

JDBC?学习笔记(二)——?大数据+存储过程+批处理+事务

??????链接地址:http://even2012.iteye.com/blog/1886950

?

JDBC?学习笔记(三)——?数据源(数据库连接池):DBCP数据源、C3P0?数据源以及自定义数据源技术

??????链接地址:http://even2012.iteye.com/blog/1886953

?

JDBC?学习笔记(四)——?自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表??

??????链接地址:http://even2012.iteye.com/blog/1886956

?

?

?学习小结

?

?

?

?

?

?

?

?

?

?

?

?

1、自定义JDBC框架?——数据库元数据:DataBaseMetaData

?

元数据:数据库、表、列的定义信息。

?

DataBaseMetaData?? connection.getDatabaseMetaData()????

?

获得代表DataBaseMetaData 对象元数据的DataBaseMetaData 对象。

?

????DataBaseMetaData对象中的方法:

?

????????(1) getURL():返回一个String类对象,代表数据库的URL。

?

????????(2) getUserName():返回连接当前数据库管理系统的用户名。

?

????????(3) getDatabaseProductName():返回数据库的产品名称。

?

????????(4) getDatabaseProductVersion():返回数据库的版本号。

?

????????(5) getDriverName():返回驱动驱动程序的名称。

?

????????(6) getDriverVersion():返回驱动程序的版本号。

?

????????(7) isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。

?

?

?

Demo样例:?获取数据库的元数据?

?

??public?void?test1()?throws?SQLException{

?

????????Connection?conn?=?JdbcUtils_C3P0.getConnection();

?

????????DatabaseMetaData?meta?=?conn.getMetaData();

?

????????System.out.println(meta.getDatabaseProductName());

?

????????System.out.println(meta.getDatabaseMajorVersion());

?

????????System.out.println(meta.getDatabaseMinorVersion());

?

??}?

?

?

?

?

?

?

2、自定义JDBC框架?——数据库元数据:DataBaseMetaData

?

ParameterMetaData?? PreparedStatement . getParameterMetaData()

?

获得代表PreparedStatement元数据的ParameterMetaData对象。

?

例如:SQL语句 “ Select * from user where name=? And password=?? ” 中的两个“ ?” 问号。

?

ParameterMetaData对象 中的方法:

?

????????(1) getParameterCount()????--获得指定参数的个数

?

????????(2) getParameterType(int param)????--?获得指定参数的sql类型(Mysql数据库不支持该方法,会报异常。)

?

?

?

Demo样例:参数元数据

?

??????public?void?test2()?throws?SQLException{

?

????????????Connection?conn?=?JdbcUtils_C3P0.getConnection();

?

????????????String?sql?=?"insert?into?user(id,name)?values(?,?)";

?

?????????

?

????????????PreparedStatement?st?=?conn.prepareStatement(sql);

?

????????????ParameterMetaData?meta?=?st.getParameterMetaData();

?

?????????

?

????????????System.out.println(meta.getParameterCount());

?

????????????System.out.println(meta.getParameterType(1));?

?

??????}

?

?

?

?

?

?

3、自定义JDBC框架?——结果集元数据: ResultSetMetaData

?

ResultSetMetaData?? ResultSet. getMetaData()

?

获得代表ResultSet对象元数据的ResultSetMetaData对象。

?

????ResultSetMetaData对象中的方法

?

????????????(1) getColumnCount()????--?返回resultset对象的列数

?

????????????(2) getColumnName(int column)????--?获得指定列的名称

?

????????????(3) getColumnTypeName(int column)????--?获得指定列的类型

?

?

?

Demo样例: 结果集元数据

?

??????public?void?test3()?throws?SQLException{

?

????????????Connection?conn?=?JdbcUtils_C3P0.getConnection();

?

????????????String?sql?=?"select?*?from?account";

?

????????????PreparedStatement?st?=?conn.prepareStatement(sql);

?

????????????ResultSet?rs?=?st.executeQuery();

?

?????????

?

????????????ResultSetMetaData??meta?=?rs.getMetaData();

?

????????????System.out.println(meta.getColumnCount());

?

????????????System.out.println(meta.getColumnName(1));

?

????????????System.out.println(meta.getColumnName(2));

?

????????????System.out.println(meta.getColumnName(3));????

?

??????}

?

?

?

?

?

??

?

4、使用元数据简化JDBC代码

?

业务背景:系统中所有实体对象都涉及到基本的CRUD操作:

?

????????(1) 万能更新

?

????????所有实体的CUD操作代码基本相同,仅仅发送给数据库的SQL语句不同而已,因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的SQL语句。

?

?

?

Demo样例1:万能更新的方法内容部分

?

????public?static?void?update(String?sql,Object?params[])?throws?SQLException{

?

????????Connection?conn?=?null;

?

????????PreparedStatement?st?=?null;

?

????????ResultSet?rs?=?null;

?

????????try{

?

??????????????conn?=?getConnection();

?

??????????????st?=?conn.prepareStatement(sql);

?

??????????????for(int?i=0;i<params.length;i++){

?

????????????????????st.setObject(i+1,params[i]);

?

??????????????}

?

??????????????st.executeUpdate();

?

????????}finally{

?

??????????????release(conn,?st,?rs);

?

????????}

?

??}

?

?

?

Demo样例2:万能更新方法的调用代码

?

????public?class?CustomerDaoImpl?implements?CustomerDao?{?

?

??????????public?void?add(Customer?c){

?

????????????????try{

?

??????????????????????String?sql?=?"insert?into?customer(id,name,gender,birthday,cellphone,email,preference,type,description)?values(?,?,?,?,?,?,?,?,?)";

?

??????????????????????Object?params[]?=?{c.getId(),c.getName(),c.getGender(),c.getBirthday(),c.getCellphone(),c.getEmail(),c.getPreference(),c.getType(),c.getDescription()};

?

??????????????????????JdbcUtils.update(sql,?params);

?

????????????????}catch?(Exception?e)?{

?

??????????????????????throw?new?DaoException(e);

?

????????????????}

?

??????????}

?

?????

?

??????????public?void?update(Customer?c){???//id

?

????????????????try{

?

??????????????????????String?sql?=?"update?customer?set?name=?,gender=?,birthday=?,cellphone=?,email=?,preference=?,type=?,description=???where?id=?";

?

??????????????????????Object?params[]?=?{c.getName(),c.getGender(),c.getBirthday(),c.getCellphone(),c.getEmail(),c.getPreference(),c.getType(),c.getDescription(),c.getId()};

?

??????????????????????JdbcUtils.update(sql,?params);

?

????????????????}catch?(Exception?e)?{

?

??????????????????????throw?new?DaoException(e);

?

????????????????}?

?

??????????}

?

?????

?

??????????public?void?delete(String?id){

?

????????????????try{

?

??????????????????????String?sql?=?"delete?from?customer?where?id=?";

?

??????????????????????Object?params[]?=?{id};

?

??????????????????????JdbcUtils.update(sql,?params);

?

????????????????}catch?(Exception?e)?{

?

??????????????????????throw?new?DaoException(e);

?

????????????????}?

?

??????????}?

?

????}

?

??

?

????????(2)?万能查询

?

????????实体的R操作,除SQL语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,因此可义一个query方法,除以参数形式接收变化的SQL语句外,可以使用策略模式由qurey方法的调用者决定如何把ResultSet中的数据映射到实体对象中。

?

?????????备注:关于自定义万能查询的代码,涉及到自定义处理器等代码,上面所述的数据库元数据的各种知识也都应用到其中,故有些复杂,不便学习。有万能查询需求的请学习Apache—DBUtils框架 中的查询方法部分,相对来说只要会调用即可,学习成本会小一些。

?

?

?

?

?

?

?

5、Apache—DBUtils框架简介

?

????????commons-dbutils?是?Apache?组织提供的一个开源?JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。因此dbutils成为很多不喜欢hibernate的公司的首选。

?

????????工具类:????org.apache.commons.dbutils.DbUtils。???

?

?

?

????????API介绍:

?

???????????(1) ?org.apache.commons.dbutils.QueryRunner?

?

???????????(2)? org.apache.commons.dbutils.ResultSetHandler

?

?????????

?

?

?

?

6、DbUtils类?介绍

?

????????DbUtils?:提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:

?

????????(1) public?static?void?close(…)?throws?java.sql.SQLException: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。

?

????????(2) public?static?void?closeQuietly(…):?这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLException。

?

????????(3) public?static?void?commitAndCloseQuietly(Connection?conn):?用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。?

?

????????(4) public?static?boolean?loadDriver(java.lang.String?driverClassName):这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。

?

?

?

?

?

?

7、QueryRunner类 介绍

?

????????该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。

?

????????QueryRunner类提供了两个构造方法:

?

????????????(1) 默认的构造方法:

?

????????????????????QueryRunner()?

?

????????????(2) 需要一个?javax.sql.DataSource?来作参数的构造方法。

?

????????????????????QueryRunner(DataSource?ds)?

?

?

?

?

?

?

8、QueryRunner类的主要方法

?

????????(1) public?Object?query(Connection?conn,?String?sql,?Object[]?params,?ResultSetHandler?rsh)?throws?SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理?PreparedStatement?和?ResultSet?的创建和关闭。

?

????????(2) public?Object?query(String?sql,?Object[]?params,?ResultSetHandler?rsh)?throws?SQLException: 几乎与第一种方法一样;唯一的不同在于它不将数据库连接提供给方法,并且它是从提供给构造方法的数据源(DataSource)?或使用的setDataSource?方法中重新获得?Connection。?????????

?

????????(3) public?Object?query(Connection?conn,?String?sql,?ResultSetHandler?rsh)?throws?SQLException?:?执行一个不需要置换参数的查询操作。?????????

?

????????(4) public?int?update(Connection?conn,?String?sql,?Object[]?params)?throws?SQLException:用来执行一个更新(插入、更新或删除)操作。????????

?

????????(5) public?int?update(Connection?conn,?String?sql)?throws?SQLException:用来执行一个不需要置换参数的更新操作。

?

?

?

Demo样例:使用dbutils完成数据库的crud?

?

public?class?Demo1?{?

?

??/*

?

???create?database?day17;

?

???use?day17;

?

???create?table?users(

?

????id?int?primary?key,

?

????name?varchar(40),

?

????password?varchar(40),

?

????email?varchar(60),

?

????birthday?date

?

??);

?

???*/?

?

??@Test

?

??public?void?insert()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"insert?into?users(id,name,password,email,birthday)?values(?,?,?,?,?)";

?

????Object?params[]?=?{2,"bbb","123","aa@sina.com",new?Date()};

?

????runner.update(sql,?params);

?

??}

?

?

?

??@Test

?

??public?void?update()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"update?users?set?email=??where?id=?";

?

????Object?params[]?=?{"aaaaaa@sina.com",1};

?

????runner.update(sql,?params);

?

??}

?

?

?

??@Test

?

??public?void?delete()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"delete?from?users?where?id=?";

?

????runner.update(sql,?1);

?

??}

?

?

?

??@Test

?

??public?void?find()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"select?*?from?users?where?id=?";

?

????User?user?=?(User)?runner.query(sql,?1,?new?BeanHandler(User.class));

?

????System.out.println(user.getEmail());

?

??}

?

?

?

?

?

??@Test

?

??public?void?getAll()?throws?Exception{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"select?*?from?users";

?

????List?list?=?(List)?runner.query(sql,?new?BeanListHandler(User.class));

?

????System.out.println(list);

?

??}

?

?

?

??@Test

?

??public?void?batch()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=??"insert?into?users(id,name,password,email,birthday)?values(?,?,?,?,?)";

?

????Object?params[][]?=?new?Object[3][5];

?

????for(int?i=0;i<params.length;i++){??//3

?

??????params[i]?=?new?Object[]{i+1,"aa"+i,"123",i?+?"@sina.com",new?Date()};

?

????}

?

????runner.batch(sql,?params);

?

??}

?

}

?

?

?

?

?

??

?

9、ResultSetHandler接口?介绍

?

????????该接口用于处理?java.sql.ResultSet,将数据按要求转换为另一种形式。

?

????????ResultSetHandler?接口提供了一个单独的方法:Object?handle?(java.sql.ResultSet?.rs)。

?

????????

?

?

?

?

10、ResultSetHandler?接口的实现类

?

??????? (1)?ArrayHandler( ):把结果集中的第一行数据转成对象数组。

?

????????(2) ArrayListHandler( ):把结果集中的每一行数据都转成一个数组,再存放到List中。

?

????????(3) BeanHandler(Class?type)?:将结果集中的第一行数据封装到一个对应的JavaBean实例中。

?

????????(4) BeanListHandler(Class?type)?:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。

?

????????(5) ColumnListHandler(int?columnIndex?/?String?columnName):将结果集中某一列的数据存放到List中。

?

?????? ?(6)?KeyedHandler( int?columnIndex?/?String?columnName ):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,并将其columnName的值作为指定的key。

?

??????? (7)?MapHandler( ):将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。

?

????????(8) MapListHandler( ):将结果集中的每一行数据都封装到一个Map里,然后再存放到List

?

?????? ?(9)??ScalarHandler( ):将结果集中的某一列?装入到一个对象中。

?

?

?

Demo样例:测试dbutils的各个结果集处理器

?

public?class?Demo2?{???

?

??@Test

?

??public?void?test1()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"select?*?from?users?where?id=?";

?

????Object?result[]?=?(Object[])?runner.query(sql,1,?new?ArrayHandler());

?

????System.out.println(result[0]);

?

????System.out.println(result[1]);

?

??}??

?

?

?

??@Test

?

??public?void?test2()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"select?*?from?users";

?

????List?list?=?(List)?runner.query(sql,?new?ArrayListHandler());

?

????System.out.println(list);

?

??}

?

?

?

??@Test

?

??public?void?test3()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"select?*?from?users";

?

????List?list?=?(List)?runner.query(sql,?new?ColumnListHandler1("name"));

?

????System.out.println(list);

?

??}??

?

?

?

??@Test

?

??public?void?test4()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"select?*?from?users";

?

????Map<Integer,Map<String,Object>>?map?=?(Map)?runner.query(sql,?new?KeyedHandler("id"));

?

????for(Map.Entry<Integer,Map<String,Object>>?me?:?map.entrySet()){

?

??????int?id?=?me.getKey();

?

??????for(Map.Entry<String,?Object>?entry?:?me.getValue().entrySet()){

?

????????String?name?=?entry.getKey();

?

????????Object?value?=?entry.getValue();

?

????????System.out.println(name?+?"="?+?value);

?

??????}

?

????}

?

??}

?

?

?

??@Test??//获取总记录数。

?

??public?void?test5()?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"select?count(*)?from?users";

?

????/*?方式一:

?

????Object?result[]?=?(Object[])?runner.query(sql,?new?ArrayHandler());

?

????long?totalrecord?=?(Long)result[0];

?

????int?num?=?(int)totalrecord;

?

????System.out.println(num);

?

????int?totalrecord?=?((Long)result[0]).intValue();

?

????*/

?

?

?

????//方式二:

?

????int?totalrecord?=?((Long)runner.query(sql,?new?ScalarHandler(1))).intValue();

?

????System.out.println(totalrecord);

?

??}

?

}

?

?

?

//自定义

?

class?ColumnListHandler1?implements?ResultSetHandler{?

?

??private?String?columnName;

?

??public?ColumnListHandler1(String?columnName){

?

????this.columnName?=?columnName;

?

??}

?

??public?Object?handle(ResultSet?rs)?throws?SQLException?{

?

????List?list?=?new?ArrayList();

?

????while(rs.next()){

?

??????list.add(rs.getObject(columnName));

?

????}

?

????return?list;

?

??}

?

}

?

?

?

?

??

?

11、JDBC应用的事务管理(ThreadLocal类)?

?

JDBC?应用的事务管理——Service层和Dao层事务的传递。

?

????方式一:跨层传递方法参数——在Service层创建开启事务的连接,并传递到Dao层,最后在Service层提交事务;

?

????方式二:ThreadLocal 绑定连接——使用ThreadLocal进行事务管理——ThreadLocal可以实现在线程范围内实现数据共享。

?

?????方式三:使用Spring进行事务管理;(在Spring 博文中讲解。)

?

?????

?

????????????????????

?

?

?

?

?

?

12、JDBC应用的事务管理——采用跨层跨层传递方法参数

?

思想:在Service层创建开启事务的连接,并传递到Dao层,最后在Service层提交事务;

?

?

?

Demo样例1:Service层(Dao层中只要在方法中参数中接收该 连接参数 就好了)

?

public?class?BusinessService?{??

?

??/*??

?

??create?table?account(

?

????id?int?primary?key?auto_increment,

?

????name?varchar(40),

?

????money?float

?

??)character?set?utf8?collate?utf8_general_ci;

?

?

?

??insert?into?account(name,money)?values('aaa',1000);

?

??insert?into?account(name,money)?values('bbb',1000);

?

??insert?into?account(name,money)?values('ccc',1000);?

?

??*/??

?

?

?

??public?void?transfer1(int?sourceid,int?targetid,double?money)?throws?SQLException{

?

?

?

????Connection?conn?=?null;

?

????try{

?

??????//?获取连接并开启事务。

?

??????conn?=?JdbcUtils.getConnection();

?

??????conn.setAutoCommit(false);

?

?

?

??????//?将开启事务的连接传递到各层。

?

??????AccountDao?dao?=?new?AccountDao(conn);

?

?

?

??????Account?a?=?dao.find(sourceid);???//select

?

??????Account?b?=?dao.find(targetid);???//select

?

?

?

??????a.setMoney(a.getMoney()-money);??

?

??????b.setMoney(b.getMoney()+money);???

?

?

?

??????dao.update(a);?//update??????

?

??????dao.update(b);//update

?

?

?

??????//?提交事务。

?

??????conn.commit();

?

????}finally{

?

??????//?关闭连接。

?

??????if(conn!=null)?conn.close();

?

????}

?

??}

?

?

?

?

?

?

?

?

?

?

?

?

13、JDBC应用的事务管理—— ThreadLocal 绑定连接

?

思想:在Service层将开启事务的连接绑定到ThreadLocal中,在当前线程所途径的其他各层从ThreadLocal中获取连接并进行操作,最后线程返回至Service层时,再提交事务,移除绑定的链接。

?

?
JDBC-自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表
?

?

Demo样例1:将 使用ThreadLocal 绑定连接 的代码封装成工具类。

?

public?class?JdbcUtils?{

?

??private?static?DataSource?ds;

?

?

?

??//?为保证各层的类所使用的ThreadLocal是同一个,建议将其设定成静态的,但是一定要记得使用后要移出绑定在上面的对象。

?

??private?static?ThreadLocal<Connection>?tl?=?new?ThreadLocal<Connection>();??// 其实就是一个Map集合

?

?

?

??static{

?

????try{

?

??????Properties?prop?=?new?Properties();

?

??????InputStream?in?=?JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");

?

??????prop.load(in);

?

??????BasicDataSourceFactory?factory?=?new?BasicDataSourceFactory();

?

??????ds?=?factory.createDataSource(prop);

?

????}catch?(Exception?e)?{

?

??????throw?new?ExceptionInInitializerError(e);

?

????}

?

??}

?

?

?

??public?static?DataSource?getDataSource(){

?

????return?ds;

?

??}

?

?

?

??//?备注:该获取连接的方法,仅当使用ThreadLocal来管理事务连接的情况,因为向静态对象ThreadLocal中绑定了对象,所以当我们不需要管理事务的普通获取连接的方法,就不要用此方法。应该用普通的获取连接的方法。

?

??public?static?Connection?getConnection()?throws?SQLException{

?

????try{

?

??????//得到当前线程上绑定的连接

?

??????Connection?conn?=?tl.get();

?

??????if(conn==null){??//代表线程上没有绑定连接

?

????????conn?=?ds.getConnection();

?

????????tl.set(conn);

?

??????}

?

??????return?conn;

?

????}catch?(Exception?e)?{

?

??????throw?new?RuntimeException(e);

?

????}

?

??}?

?

?

?

??public?static?void?startTransaction(){

?

????try{

?

??????//得到当前线程上绑定连接开启事务

?

??????Connection?conn?=?tl.get();

?

??????if(conn==null){??//代表线程上没有绑定连接

?

????????conn?=?ds.getConnection();

?

????????tl.set(conn);

?

??????}

?

??????conn.setAutoCommit(false);

?

????}catch?(Exception?e)?{

?

??????throw?new?RuntimeException(e);

?

????}

?

??}?

?

?

?

??public?static?void?commitTransaction(){

?

????try{

?

??????Connection?conn?=?tl.get();

?

??????if(conn!=null){

?

????????conn.commit();

?

??????}

?

????}catch?(Exception?e)?{

?

??????throw?new?RuntimeException(e);

?

????}

?

??}

?

?

?

??public?static?void?closeConnection(){

?

????try{

?

??????Connection?conn?=?tl.get();

?

??????if(conn!=null){

?

????????conn.close();

?

??????}

?

????}catch?(Exception?e)?{

?

??????throw?new?RuntimeException(e);

?

????}finally{

?

??????tl.remove();???//千万注意,解除当前线程上绑定的链接(从threadlocal容器中移除对应当前线程的链接)

?

????}

?

??}

?

}

?

?

?

Demo样例2: 采用 ThreadLocal 绑定连接 来管理事务的 Service层的代码。

?

public?class?BusinessService?{??

?

??/*??

?

??create?table?account(

?

????id?int?primary?key?auto_increment,

?

????name?varchar(40),

?

????money?float

?

??)character?set?utf8?collate?utf8_general_ci;

?

?

?

??insert?into?account(name,money)?values('aaa',1000);

?

??insert?into?account(name,money)?values('bbb',1000);

?

??insert?into?account(name,money)?values('ccc',1000);?

?

??*/??

?

??//用上ThreadLocal的事务管理

?

??public?void?transfer2(int?sourceid,int?targetid,double?money)?throws?SQLException{

?

?

?

????try{

?

??????JdbcUtils.startTransaction();

?

??????AccountDao?dao?=?new?AccountDao();

?

??????Account?a?=?dao.find(sourceid);???//select

?

??????Account?b?=?dao.find(targetid);???//select

?

??????a.setMoney(a.getMoney()-money);??

?

??????b.setMoney(b.getMoney()+money);???

?

??????dao.update(a);?//update

?

??????dao.update(b);//update

?

??????JdbcUtils.commitTransaction();

?

????}finally{

?

??????JdbcUtils.closeConnection();

?

????}

?

??}

?

}

?

?

?

??

?

14、使用JDBC操作多个表

?

????????(1) 使用JDBC操作多表的步骤

?

????????????????(a)??明确对象的属性,及之间的关联关系。

?

????????????????(b)??明确表关系,?创建数据库及表;

?

????????????????(c)? 编码Dao层的代码(重点是增删改查时涉及到的级联操作。)

?

????????????????(d)? 编码Service层的代码(重点是 复杂对象? 的级联操作。)

?

????????

?

????????(2)? O-R Mapping 映射的注意事项

?

????????????????(a) 不管java的对象存在何种关系,反映到关系型数据库中,都是使用外键表示纪录(即对象)的关联关系。

?

????????????????(b) 设计java对象如涉及到多个对象相互引用,要尽量避免使用一对多,或多对多关系,而应使用多对一描述对象之间的关系(或使用延迟加载的方式)。以避免查询出了所有“一对多”中?“多”的数据,容易造成内存溢出

?

????????????????(c) 特殊情况下(比如订单--订单项)必须设计成“一对多”关系时,当“多”的一方数据较少时,可以使用级联查询,但若是“多”的一方数据量较大时,则建议使用?“分页方式”查询。?

?

????????

?

?????????(3) ?“一对多”多表关联关系的设计方法:

?

????????????????(a) 先将每张表各自的基本属性信息列好;

?

????????????????(b) 再将“一对多”?多的一方中设定外键列(并添加外键约束,以维护两表之间的关系)。

?

?????????

?

????????(4) 常用O-R?Mapping映射工具

?

????????????????(a) Hibernate

?

?????????????? ?(b)?Ibatis

?

????????????????(c) Commons?DbUtils(只是对JDBC简单封装)

?

?????????

?

?

?

?

?

?

?

15、使用JDBC操作多个表—— 一对多关系 (例如:部门和员工)

?


JDBC-自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表
?

?

?

?

?

?

Demo样例1:Dao层的代码

?

public?class?DepartmentDao?{?

?

??/*

?

????多表设计原则

?

????1、现将各表各自的基本属性信息列好;

?

????2、再将“一对多”?多的一方中设定外键列(并添加外键约束,以维护两表之间的关系)。

?

?

?

????create?table?department

?

????(

?

??????id?varchar(40)?primary?key,

?

??????name?varchar(40)

?

????);?

?

????create?table?employee

?

????(

?

??????id?varchar(40)?primary?key,

?

??????name?varchar(40),

?

??????salary?double,

?

??????department_id?varchar(40),

?

??????constraint?department_id_FK?foreign?key(department_id)?references?department(id)

?

????);

?

?

?

????alter?table?employee?drop?foreign?key?department_id_FK;

?

????alter?table?employee?add?constraint?department_id_FK?foreign?key(department_id)?references?department(id)?on?delete?set?null;

?

?

?

????alter?table?employee?drop?foreign?key?department_id_FK;

?

????alter?table?employee?add?constraint?department_id_FK?foreign?key(department_id)?references?department(id)?on?delete?cascade;?

?

???*/

?

?

?

??public?void?add(Department?d)?throws?SQLException{?

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

?

?

????//1.把department对象的数据插入到department表

?

????String?sql?=?"insert?into?department(id,name)?values(?,?)";

?

????Object?params[]?=?{d.getId(),d.getName()};

?

????runner.update(sql,?params);

?

?

?

????//2.把department对象中维护的所有员工插入到员工表

?

????Set<Employee>?set?=?d.getEmployees();

?

????for(Employee?e?:?set){

?

??????sql?=?"insert?into?employee(id,name,salary,department_id)?values(?,?,?,?)";

?

??????params?=?new?Object[]{e.getId(),e.getName(),e.getSalary(),d.getId()};

?

??????runner.update(sql,?params);

?

????}

?

?

?

????//3.更新员工表的外键列,说明员工的部门(本例中的ID可以实现给定,固就不需要进行更新外键列操作;但若是涉及到获取 自动生成主键 的案例时,则需要 涉及到更新外键操作)。

?

????

?

??}

?

?

?

?

?

??//该方法查询出了所有“一对多”中?“多”的数据,容易造成内存溢出。当“多”的一方数据较少时,可以使用该级联查询,但若是“多”的一方数据量较大时,则建议使用?“分页方式”查询。

?

??public?Department?find(String?id)?throws?SQLException{

?

?

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

?

?

????//1.找部门表,查出部门的基本信息

?

????String?sql?=?"select?*?from?department?where?id=?";

?

????Department?d?=?(Department)?runner.query(sql,?id,?new?BeanHandler(Department.class));

?

?

?

????//2.找员工表,找出部门下面所有员工

?

????sql?=?"select?*?from?employee?where?department_id=?";

?

????List?list?=?(List)?runner.query(sql,?id,?new?BeanListHandler(Employee.class));

?

?

?

????d.getEmployees().addAll(list);????// 注:set集合的addAll() 是将所有的值逐个取出来,再逐一存入到Set集合中;而set集合的add()方法则是替换一Set集合的引用。

?

?

?

????return?d;

?

??}

?

??//111

?

??public?void?delete(String?id)?throws?SQLException{

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql=?"delete?from?department?where?id=?";

?

????runner.update(sql,?id);

?

??}

?

}

?

?

?

Demo样例2:Service层的代码?

?

public?class?BService?{?

?

@Test

?

??public?void?add()?throws?SQLException{?

?

????Department?d?=?new?Department();

?

????d.setId("111");

?

????d.setName("开发部");

?

?

?

????Employee?e1?=?new?Employee();

?

????e1.setId("1");

?

????e1.setName("aa");

?

????e1.setSalary(10000);?

?

?

?

????Employee?e2?=?new?Employee();

?

????e2.setId("2");

?

????e2.setName("bb");

?

????e2.setSalary(10000);

?

??

?

????d.getEmployees().add(e1);

?

????d.getEmployees().add(e2);?

?

?

?

????DepartmentDao?dao?=?new?DepartmentDao();

?

????dao.add(d);

?

??}

?

?

?

??@Test

?

??public?void?find()?throws?SQLException{

?

????DepartmentDao?dao?=?new?DepartmentDao();

?

????Department?d?=?dao.find("111");

?

????System.out.println(d);

?

??}

?

?

?

??@Test

?

??public?void?delete()?throws?SQLException{

?

????DepartmentDao?dao?=?new?DepartmentDao();

?

????dao.delete("111");

?

??}

?

?}

?

?

?

?

?

?

16、使用JDBC操作多个表—— 多对多关系 (老师和学生)

?


JDBC-自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表
?

?

?

?

Demo样例1:Dao层的代码

?

public?class?TeacherDao?{?

?

??/*

?

??create?table?teacher

?

??(

?

????id?varchar(40)?primary?key,

?

????name?varchar(40),

?

????salary?double

?

??)?;

?

?

?

??create?table?student

?

??(

?

????id?varchar(40)?primary?key,

?

????name?varchar(40)

?

??);

?

?

?

???create?table?teacher_student

?

???(

?

?????teacher_id?varchar(40),

?

?????student_id?varchar(40),

?

?????primary?key(teacher_id,student_id),

?

?????constraint?teacher_id_FK?foreign?key(teacher_id)?references?teacher(id),?

?

?????constraint?student_id_FK?foreign?key(student_id)?references?student(id)

?

???);

?

?

?

???alter?table?teacher_student?drop?foreign?key?teacher_id_FK;

?

???alter?table?teacher_student?add?constraint?teacher_id_FK?foreign?key(teacher_id)?references?teacher(id)?on?delete?cascade;??

?

?

?

???alter?table?teacher_student?drop?foreign?key?student_id_FK;

?

???alter?table?teacher_student?add?constraint?student_id_FK?foreign?key(student_id)?references?student(id)?on?delete?cascade;

?

??*/

?

?

?

??public?void?add(Teacher?t)?throws?SQLException?{

?

?

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

?

?

????//1`.取出老师存老师表

?

????String?sql?=?"insert?into?teacher(id,name,salary)?values(?,?,?)";

?

????Object?params[]?=?{t.getId(),t.getName(),t.getSalary()};

?

????runner.update(sql,?params);

?

?

?

?

?

????//2.取出老师所有学生的数据,存学生表

?

????Set<Student>?set?=?t.getStudents();

?

????for(Student?s?:?set){

?

??????sql?=?"insert?into?student(id,name)?values(?,?)";

?

??????params?=?new?Object[]{s.getId(),s.getName()};

?

??????runner.update(sql,?params);

?

?

?

??????//3.更新中间表,说明老师和学生的关系

?

??????sql?=?"insert?into?teacher_student(teacher_id,student_id)?values(?,?)";

?

??????params?=?new?Object[]{t.getId(),s.getId()};

?

??????runner.update(sql,?params);

?

????}

?

??}

?

?

?

??public?Teacher?find(String?id)?throws?SQLException{

?

?

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

?

?

????//1.找老师表,找出老师的基本信息

?

????String?sql?=?"select?*?from?teacher?where?id=?";

?

????Teacher?t?=?(Teacher)?runner.query(sql,?id,?new?BeanHandler(Teacher.class));

?

?

?

????//2.找出老师的所有学生????()

?

????//sql?=?"select?s.*?from?teacher_student?ts,student?s?where?ts.teacher_id=??and?ts.student_id=s.id";

?

????sql?=?"select?s.*?from?teacher_student?ts,student?s?where?ts.teacher_id=??and?ts.student_id=s.id";

?

????List?list?=?(List)?runner.query(sql,?id,?new?BeanListHandler(Student.class));

?

?

?

?

?

????t.getStudents().addAll(list);

?

????return?t;

?

??}

?

?

?

??public?void?delete(String?id){

?

????QueryRunner?runner?=?new?QueryRunner(JdbcUtils.getDataSource());

?

????String?sql?=?"delete?from?teacher?where?id=?";

?

?

?

??}

?

}

?

?

?

Demo样例2:Service层的代码?

?

public?class?BService?{

?

@Test

?

?public?void?addTeacher()?throws?SQLException{

?

?

?

??Teacher?t?=?new?Teacher();

?

??t.setId("1");

?

??t.setName("老张");

?

??t.setSalary(100000);

?

?

?

??Student?s1?=?new?Student();

?

??s1.setId("1");

?

??s1.setName("aa");

?

?

?

??Student?s2?=?new?Student();

?

??s2.setId("2");

?

??s2.setName("bb");

?

?

?

??t.getStudents().add(s1);

?

??t.getStudents().add(s2);?

?

?

?

??TeacherDao?dao?=?new?TeacherDao();

?

??dao.add(t);

?

?}

?

?

?

?@Test

?

?public?void?findTeacher()?throws?SQLException{

?

??TeacherDao?dao?=?new?TeacherDao();

?

??Teacher?t?=?dao.find("1");

?

??System.out.println(t);

?

?}

?

?

?

}

?

?

?

?

?

??

?

17、数据库端——表关系间的级联操作

?

表关系间的级联操作:

?

????REFERENCES?tbl_name?[(index_col_name,...)]

?

???????????????[MATCH?FULL?|?MATCH?PARTIAL?|?MATCH?SIMPLE]

?

???????????????[ON?DELETE?reference_option]??(级联删除)??

?

???????????????[ON?UPDATE?reference_option]??(级联修改)

?

?

?

reference_option的可选值:

?

????RESTRICT?|?CASCADE(删除)?|?SET?NULL(置空)?|?NO?ACTION?

?

?

?

Demo:给表添加外键约束——包含级联删除(置空)的关系

?

?? alter?table?employee?add?constraint?department_id_FK?foreign?key(department_id)?references?department(id)?on?delete?set?null?;?

?

???alter?table?employee?add?constraint?department_id_FK?foreign?key(department_id)?references?department(id)?on?delete?set?null;

?

????alter?table?employee?add?constraint?department_id_FK?foreign?key(department_id)?references?department(id)?on?delete?cascade;?

?

热点排行