JDBC 学习笔记(四)—— 自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表
2014-01-22 16:44
567 查看
本文目录:
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、数据库端——表关系间的级联操作
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:万能更新的方法内容部分
Demo样例2:万能更新方法的调用代码
(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
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的各个结果集处理器
11、JDBC应用的事务管理(ThreadLocal类)
JDBC 应用的事务管理——Service层和Dao层事务的传递。
方式一:跨层传递方法参数——在Service层创建开启事务的连接,并传递到Dao层,最后在Service层提交事务;
方式二:ThreadLocal 绑定连接——使用ThreadLocal进行事务管理——ThreadLocal可以实现在线程范围内实现数据共享。
方式三:使用Spring进行事务管理。
12、JDBC应用的事务管理——采用跨层跨层传递方法参数
思想:在Service层创建开启事务的连接,并传递到Dao层,最后在Service层提交事务;
Demo样例1:Service层(Dao层中只要在方法中参数中接收该 连接参数 就好了)
13、JDBC应用的事务管理—— ThreadLocal 绑定连接
思想:在Service层将开启事务的连接绑定到ThreadLocal中,在当前线程所途径的其他各层从ThreadLocal中获取连接并进行操作,最后线程返回至Service层时,再提交事务,移除绑定的链接
Demo样例1:将 使用ThreadLocal 绑定连接 的代码封装成工具类。
Demo样例2: 采用 ThreadLocal 绑定连接 来管理事务的 Service层的代码。
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操作多个表—— 一对多关系 (例如:部门和员工)
Demo样例1:Dao层的代码
Demo样例2:Service层的代码
16、使用JDBC操作多个表—— 多对多关系 (老师和学生)
Demo样例1:Dao层的代码
Demo样例2:Service层的代码
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;
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、数据库端——表关系间的级联操作
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进行事务管理。
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层时,再提交事务,移除绑定的链接
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操作多个表—— 一对多关系 (例如:部门和员工)
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操作多个表—— 多对多关系 (老师和学生)
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;
相关文章推荐
- JDBC 学习笔记(四)—— 自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表 - 解无邪
- JDBC 学习笔记(十)—— 使用 JDBC 搭建一个简易的 ORM 框架
- java安全框架-Shiro学习笔记(七)-自定义realm
- JDBC 学习笔记(三)—— 数据源(数据库连接池):DBCP数据源、C3P0 数据源以及自定义数据源技术
- JDBC 学习笔记(三)—— 数据源(数据库连接池):DBCP数据源、C3P0 数据源以及自定义数据源技术
- 关于框架学习的简单笔记
- 韩顺平PHP学习视频笔记整理005无序列表 有序列表 框架
- iOS学习笔记-090.彩票05——购彩大厅2_自定义蒙版、popMenu、UIView分类抽取
- CI框架学习笔记
- StringTemplate.Net 学习笔记(6):自定义输出格式
- 集合框架map学习笔记一IdentityHashMap
- Sharepoint学习笔记—Ribbon系列-- 7. 在Ribbon中替换指定控件(针对用户自定义Tab)
- 学习笔记之——自定义带滑动距离监控和仿iOS回弹效果的ScrollView
- Perl 字符串操作 以及 自定义排序学习笔记
- OC学习笔记之Foundation框架NSNumber、NSValue和NSDate
- opengl学习笔记2-1-基本的运行框架
- ArcGIS API for JavaScript 4.2学习笔记[15] 弹窗内容的格式与自定义格式
- 学习ASP.NET MVC5框架揭秘笔记目录
- 【学习笔记】Silverlight框架:Jounce(6)——Command和ViewModel
- Django框架学习笔记(windows环境下安装)