除去直接调用开源组织给提供的jar包外,我今天要说的内容就是JDBC的最终版,需要我们多敲多练多理解。最重要的是理解。废话不多说了,开始吧。
早上的时候,我将昨天的内容整理,能处理事务的通用方法写到了JDBCUtils工具类中。
其实到这里的时候,所有细节部分的代码都已经实现了。接下来要进行的内容,其实就是对这些内容的整合,整体的调控。
我们来说DAO:
现在我们希望这个程序能更加自动化一点,我们只需要提供一个连接,它就能返回给我们一个对象或一个对象集,或一个结果。或是我们提供一个连接,一个对象,它就能自动的实现增删改。那么DAO就是这样产生的。
应用泛型类,我们将DAO设计成适用于可操作不同对象的增删改查的父类。具体的操作 由操纵具体实体类 的子类DAO 来完成。
来看代码:
DAO:
public class Dao<T> {
Class<T> clazz = null;
@SuppressWarnings("unchecked")
public Dao(){
Type type = this.getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) type;
Type[] types = pt.getActualTypeArguments();
clazz = (Class<T>) types[0];
System.out.println(clazz);
}
protected List<T> getGroupValue(Connection conn, String sql, Object...args){
List<T> list = new ArrayList<T>();
// get PreparedStatement‘s object
PreparedStatement ps = null;
// execute sql
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
// set ps
for(int i = 0; i < args.length; i++){
ps.setObject(i+1, args[i]);
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
System.out.println(columnCount);
while(rs.next()){
T t = clazz.newInstance();
for(int i = 1; i <= columnCount; i++){
// read
String columnName = rsmd.getColumnLabel(i);
Object columnValue = rs.getObject(columnName);
// write
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnValue);
}
list.add(t);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(rs, ps, null);
}
return list;
}
protected Object getValue(Connection conn, String sql, Object... args){
Object object = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// get PreparedStatement‘s object
ps = conn.prepareStatement(sql);
// set ps
for(int i = 0; i < args.length; i++){
ps.setObject(i+1, args[i]);
}
// execute the sql
rs = ps.executeQuery();
// read rs
if(rs.next()){
object = rs.getObject(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JDBCUtils.close(rs, ps, null);
}
return object;
}
/**
* getPrepareAllTransaction()
*
* @param conn
* @param sql
* @param clazz
* @param args
* @return
*/
protected List<T> getPrepareAllTransaction(Connection conn, String sql,
Object... args) {
List<T> list = new ArrayList<T>();
// get PreparedStatement
PreparedStatement ps = null;
// execute the sql
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
// set the ps
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
rs = ps.executeQuery();
// get the columnNum
ResultSetMetaData rsmd = rs.getMetaData();
int columnNum = rsmd.getColumnCount();
// read the rs and write to an object
while (rs.next()) {
T t = clazz.newInstance();
for (int i = 1; i <= columnNum; i++) {
// read
String columnName = rsmd.getColumnLabel(i);
Object columnVal = rs.getObject(columnName);
// through the method(reflect)
PropertyUtils.setProperty(t, columnName, columnVal);
}
list.add(t);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(rs, ps, null);
}
return list;
}
/**
* getTransacation
*
* @param conn
* @param sql
* @param clazz
* @param args
* @return
*/
protected T getPrepareTransaction(Connection conn, String sql, Object... args) {
T t = null;
// get PreparedStatement‘s object
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
// set the ps
ps.setObject(1, args[0]);
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnNum = rsmd.getColumnCount();
// read and write
if (rs.next()) {
t = clazz.newInstance();
for (int i = 1; i <= columnNum; i++) {
// read
String columnName = rsmd.getColumnLabel(i);
Object columnValue = rs.getObject(columnName);
// write
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnValue);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(rs, ps, null);
}
return t;
}
/**
* Update
*
* @param conn
* @param sql
* @param args
* @return
*/
protected int transactionUpdate(Connection conn, String sql, Object... args) {
// get preparedStatement‘s object
PreparedStatement ps = null;
// execute the ps
int rows = 0;
try {
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
rows = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(ps, null);
}
// return
return rows;
}
}
发现,里面的方法和我们之前写的方法没有什么区别,只不过因为T的声明到了DAO里,所以我们下面的方法中就不需要再次声明。同时提供了一个构造方法,方法中利用反射,获取了当前对象的类的父类的泛型类型this.getClass().getGenericSuperClass();
这是获取了父类所有泛型的类型,里面可能有一个值比如DAO<T>
,也可能存在多个值,比如Map<K, V>
,通过API我们发现,Type中没有这样的方法可以将里边的类型全部取出来,而它的子接口中提供了这样的方法。
ParameterizedType pt = (ParameterizedType) type;
getActualTypeArguments()
返回一个type[]数组。这里因为我们知道就有一个泛型类型,直接取索引为0的元素即为泛型类型。
创建一个具体的操作类:
public class UserDAO extends Dao<User>{
// select function
public Object getSpecialValue(Connection conn){
String sql = "SELECT count(*) FROM users";
return getValue(conn, sql);
}
// select All
public List<User> getAllUser(Connection conn){
String sql = "SELECT * FROM users";
return getPrepareAllTransaction(conn, sql);
}
// select info through id....
public User getUser(Connection conn, int id){
String sql = "SELECT * FROM users WHERE id = ?";
return getPrepareTransaction(conn, sql, id);
}
//delete
public int delete(Connection conn, int id){
String sql = "DELETE FROM users WHERE id = ?";
return transactionUpdate(conn, sql, id);
// update
public int update(Connection conn, User user){
String sql = "UPDATE users SET address = ? WHERE id = ?";
return transactionUpdate(conn, sql, user.getAddress(), user.getId());
}
// insert
@Test
public int insert(Connection conn, User user){
String sql = "INSERT INTO users(name, address, phone) values(?,?,?)";
int rows = transactionUpdate(conn, sql, user.getName(), user.getAddress(), user.getPhone());
return rows;
}
}
这里这个类是用来操作User类的。测试这里就不写了。还是要说一下刚刚的构造器。
我们在创建UserDao的时候,它默认的会调用UserDao的无参构造器,而又因为有继承,这个UserDao的构造器又会默认的调用父类DAO的构造器,再按照上面的步骤分析,是不是就明白了。
这样做的好处就是,我们不用在有的方法中继续重复的写Class clazz这个参数。
DAO就算说完了。
到这里为止,就要画个分割线了。之前的部分需要我们多多理解。因为这是后面学习三大框架的基础,核心。按照从进化1到最终进化这个思路,随便在一个编辑器里,从头到尾写三遍。我感觉很有必要。
————————————————华丽丽的分割线—————————————-
接下来是开源组织提供的一些工具类,他能帮我们完成上面所有的内容。当然可能他们写的更好,但是核心的思想就是上面这些。
获取连接:
推荐:c3p0
推荐理由:可以通过xml文件来进行配置。
执行SQL语句:
DbUtils()
具体的使用,参考他们提供的帮助文档。
今天实在是瞌睡的不行了,学校烦心的事情又比较多,本来想放弃更这篇博客的。但是又想了想,如果我这一放弃,就会给我以后的放弃带来更多的理由,而我克服了。我会坚持下去。加油吧,少年。