使用DbUtils编写DAO
标签(空格分隔): jdbc
DAO接口
里面定义好访问数据库的各种方法,接口传入一个参数,是DAO处理的实体类的类型
package day4;
/**
* Created by japson on 12/12/2017.
*/
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* 访问数据的DAO接口
* 里面定义好访问数据库的各种方法
* @param <T> DAO处理的实体类的类型
*/
public interface DAO<T> {
/**
* INSERT,UPDATE,DELETE
* @param connection 数据库连接
* @param sql SQL语句
* @param args 填充占位符的可变参数
*/
void update(Connection connection,String sql,Object ... args);
/**
* 返回一个T的对象
* @param connection
* @param sql
* @param args
* @return
*/
T get(Connection connection,String sql,Object... args) throws SQLException;
/**
* 返回T的一个集合
* @param connection
* @param sql
* @param args
* @return
*/
List<T> getForList(Connection connection,String sql,Object... args);
/**
* 返回具体的一个值,例如总人数,平均数,某人id等
* @param connection
* @param sql
* @param args
* @param <E>
* @return
*/
<E> E getForValue(Connection connection,String sql,Object... args);
/**
* 批量处理的方法
* @param connection
* @param sql
* @param args 填充占位符的Object[]类型的可变参数
*/
void batch(Connection connection, String sql, Object[] ... args );
}
反射获取泛型T.class
目标是在具体的应用中能够确定泛型T
具体是那个类型,也就是T.class
是什么。
那么我们如何获取泛型T的类型呢
T.getClass()
或 T.class
都是非法的,因为T是泛型变量。 由于一个类的类型在编译期已确定,根据泛型擦拭,故不能在运行期得到T自己的实际类型。 实际上,当实例化以后,Class里面就不包括T的信息了,对于Class而言,T已经被擦拭为Object,所以无法反射到T的具体类别,也就无法得到T.class
而getGenericSuperClass()是Generic继承的特例,对于这种情况,子类会保存父类的Generic参数类型,返回一个ParameterizedType(参数化类型),这是可以获取到父类的T.class,这也是子类确定应该继承什么T的方法。
getClass().getGenericSuperclass()
:返回表示此Class所表示的实体的的Type
parameterizedType.getActualTypeArguments()
:返回表示此类型实际类型参数的Type对象的数组。也就是获得父类的泛型参数的实际类型。
private Class<T> type;
/**
* 构造方法
*/
public JdbcDaoImplements() {
queryRunner = new QueryRunner();
//通过反射, 获得 Class 定义中声明的父类的泛型参数类型
//getGenericSuperclass()获得带有泛型的父类
//Type是Java中所有类型的公共高级接口。包括原始类型,参数化类型,数组类型、类型变量和基本类型
Type superClass = getClass().getGenericSuperclass();
//ParameterizedType参数化类型,即泛型
//若带有泛型的父类为ParameterizedType参数化类型,则将带有泛型的父类强转为ParameterizedType参数化类型
if(superClass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) superClass;
//getActualTypeArguments获取参数化类型的数组,泛型可能有多个
Type[] typeArgs = parameterizedType.getActualTypeArguments();
if (typeArgs[0] instanceof Class) {
//确定子类需要传入泛型的类型
type = (Class<T>) typeArgs[0];
}
}
}
JdbcDaoImplements
这是一个实现类,实现了DAO接口。
每一个方法都是通过QueryRunner来实现的
package day4;
import day2.ReflectionUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* Created by japson on 12/12/2017.
*/
/**
* 使用QueryRunner提供其DAO接口的具体实现
* @param <T> 子类需要传入泛型的类型
*/
public class JdbcDaoImplements<T> implements DAO<T> {
//使用QueryRunner类实现,因此要创建一个QueryRunner类的对象
private QueryRunner queryRunner = null;
//创建一个type,用来表示子类需要传入泛型的类型
private Class<T> type;
/**
* 构造方法
*/
public JdbcDaoImplements() {
queryRunner = new QueryRunner();
//通过反射, 获得 Class 定义中声明的父类的泛型参数类型
//getGenericSuperclass()获得带有泛型的父类
//Type是Java中所有类型的公共高级接口。包括原始类型,参数化类型,数组类型、类型变量和基本类型
Type superClass = getClass().getGenericSuperclass();
//ParameterizedType参数化类型,即泛型
//若带有泛型的父类为ParameterizedType参数化类型,则将带有泛型的父类强转为ParameterizedType参数化类型
if(superClass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) superClass;
//getActualTypeArguments获取参数化类型的数组,泛型可能有多个
Type[] typeArgs = parameterizedType.getActualTypeArguments();
if (typeArgs[0] instanceof Class) {
//确定子类需要传入泛型的类型
type = (Class<T>) typeArgs[0];
}
}
}
/**
* INSERT,DELETE,UPDATE操作
* @param connection 数据库连接
* @param sql SQL语句
* @param args 填充占位符的可变参数
* @throws SQLException
*/
@Override
public void update(Connection connection, String sql, Object... args) throws SQLException {
queryRunner.update(connection,sql,args);
}
/**
* 查询,查询结果为一个JavaBean
* @param connection 数据库连接
* @param sql SQL语句
* @param args 填充占位符的可变参数
* @return
* @throws SQLException
*/
@Override
public T get(Connection connection, String sql, Object... args) throws SQLException {
//创建BeanHandler对象时传入的Class参数对应的对象
return queryRunner.query(connection,sql,new BeanHandler<T>(type),args);
}
/**
* 获取一组对象
* @param connection
* @param sql
* @param args
* @return
* @throws SQLException
*/
@Override
public List<T> getForList(Connection connection, String sql, Object... args) throws SQLException {
//传入的Class参数对应的对象
return queryRunner.query(connection,sql, new BeanListHandler<T>(type),args);
}
/**
* 获取某一个值
* @param connection
* @param sql
* @param args
* @param <E>
* @return
* @throws SQLException
*/
@Override
public <E> E getForValue(Connection connection, String sql, Object... args) throws SQLException {
return queryRunner.query(connection,sql, new ScalarHandler<>());
}
/**
* 批量处理数据
* @param connection
* @param sql
* @param args 填充占位符的Object[]类型的可变参数
* @throws SQLException
*/
@Override
public void batch(Connection connection, String sql, Object[]... args) throws SQLException {
queryRunner.batch(connection,sql,args);
}
}
CustomerDao
继承了JdbcDaoImplements类并传递了Customer类型。
其中啥也没写
import day2.Customer;
/**
* Created by japson on 12/12/2017.
*/
public class CustomerDao extends JdbcDaoImplements<Customer> {
}
CustomerDaoTest
对CustomerDao进行测试,测试其继承的方法
package test.day4;
import day2.Customer;
import day4.CustomerDao;
import day4.JDBCTools;
import org.junit.Test;
import org.junit.Before;
import org.junit.After;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;
/**
* CustomerDao Tester.
*
* @author <Authors name>
* @since <pre>12/12/2017</pre>
* @version 1.0
*/
public class CustomerDaoTest {
@Before
public void before() throws Exception {
}
@After
public void after() throws Exception {
}
/**
* 创建一个CustomerDao的对象,用来调用其父类的方法
*/
CustomerDao customerDao = new CustomerDao();
/**
* 查询id=5的customer,返回一个javaBean
*/
@Test
public void testGet() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT id,name,email,birth FROM customers WHERE id = ?";
Customer customer = customerDao.get(connection,sql,5);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
/**
* 使用update方法从插入一条记录
*/
@Test
public void testUpdate() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "INSERT INTO customers(id,name,email,birth) VALUES(?,?,?,?)";
customerDao.update(connection,sql,9,"Steven","steven@163.com","1991-05-07");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
/**
* 查询一组数据:id为1,3,5的记录,返回javaBean的List
*/
@Test
public void testGetForList() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT id,name,email,birth FROM customers WHERE id IN(?,?,?)";
List<Customer> customers = customerDao.getForList(connection,sql,1,3,5);
System.out.println(customers);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
/**
* 查询一个值,有多少个id
*/
@Test
public void testGetForValue() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT COUNT(id) FROM customers";
Object object = customerDao.getForValue(connection,sql);
System.out.println(object);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
/**
* 批量修改数据,第一个占位符为name,第二个占位符为id
*/
@Test
public void testBatch() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "UPDATE customers SET name = ? WHERE id = ?";
//插入的是多维数据,高维代表批量处理的次数,低维代表占位符
Object[][] objects = {{"hahah7",7},{"hahah8",8},{"hahah9",9}};
customerDao.batch(connection,sql,objects);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
}