其实在操作数据的时候,会引入一个概念那就是DAO。
DAO(Data Access Object):访问数据信息的类和接口,包括了对数据的CRUD(Create ,Retrival, Update, Delete),而不包含任何业务相关的信息。又是也称作为BaseDAO.
其作用就是为了实现功能的模块化,更有利于代码的维护和升级。
其实这个会影响创建项目的时候结构。因为演示Java所以不在后面写更多的内容,简单的整理。
包的结构以及意义:
- com.test : 这个是项目的定义的,具体如何看项目规范了。
- com.test.beans: 这个是放对象类的,这个有的命名不是beans而是domain等,这个也是看如何规范了。
- com.test.dao:定义一些父类以及操作不同对象的接口
- com.test.dao.impl:实现接口的类。
- com.test.util : 这个是放一些工具类,比如得到数据库连接等
所以一般结构如下:
演示
bean 类
package com.test.beans;
public class User {
int id;
String name;
String addres;
public User() {
}
public User(int id, String name, String addres) {
this.id = id;
this.name = name;
this.addres = addres;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddres() {
return addres;
}
public void setAddres(String addres) {
this.addres = addres;
}
}
工具类
package com.test.util;
import com.mysql.jdbc.Driver;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class MysqlJDBCUtils {
// 得到一个连接
public static Connection getCon(){
Connection con=null;
Properties properties=new Properties();
try {
properties.load(MysqlJDBCUtils.class.getClassLoader().getResourceAsStream("mysql.properties"));
String user=properties.getProperty("user");
String password=properties.getProperty("password");
String url=properties.getProperty("url");
String drivername=properties.getProperty("driver");
Class dirverClass=Class.forName(drivername);
Driver dirver= (Driver) dirverClass.newInstance();
// 这一句可以省略
// DriverManager.registerDriver(dirver);
con=DriverManager.getConnection(url,user,password);
return con;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 关闭连接
public static void closeCon(Statement sts, ResultSet rst,Connection con){
if(rst!=null){
try {
rst.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if(sts!=null){
try {
sts.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if(con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
}
}
}
BaseDAO类
因为这个有些方法通用,所以将其提出了单独一个类
package com.test.dao;
import com.test.util.MysqlJDBCUtils;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.List;
// 无论操作什么数据库,其实有些方法可以提炼处理,然后通用的
// 所以写一个总父类
public class BaseDao {
// 通用的增删改
// 为什么将连接作为一个参数而不是在方法种直接调用工具类得到连接,因为要考虑兼容是否需要使用事务
// 所以在子类种得到Connection
public int updata(Connection con,String sql,Object ... args) {
PreparedStatement prst=null;
int returnint=0;
try {
prst=con.prepareStatement(sql);
int len=args.length;
for (int i = 0; i < len; i++) {
prst.setObject(i+1,args[i]);
}
// executeUpdate 返回影响的行数,如果没有影响返回0
returnint=prst.executeUpdate();
return returnint;
} catch ( Exception throwables) {
throwables.printStackTrace();
}finally {
// 因为连接是传递过来的,所以不在这里关闭连接
MysqlJDBCUtils.closeCon(prst, null,null);
}
return returnint;
}
// 返回一条数据
public <T> T getInstance(Connection con,String sql,Class<T> tClass ,Object ... args) {
PreparedStatement prst=null;
ResultSet rst=null;
int returnint=0;
try {
prst=con.prepareStatement(sql);
int len=args.length;
for (int i = 0; i < len; i++) {
prst.setObject(i+1,args[i]);
}
rst=prst.executeQuery();
ResultSetMetaData rstme= rst.getMetaData();
int columnCount=rstme.getColumnCount();
if (rst.next()) {
T t= tClass.newInstance();
for (int i = 0; i < columnCount; i++) {
String columnName = rstme.getColumnLabel(i + 1);
Field field = tClass.getField(columnName);
field.set(t,rst.getObject(i+1) );
}
return t;
}
} catch ( Exception throwables) {
throwables.printStackTrace();
}finally {
// 因为连接是传递过来的,所以不在这里关闭连接
MysqlJDBCUtils.closeCon(prst, rst,null);
}
return null;
}
// 返回一条数据
public <T> List<T> getAllInstance(Connection con, String sql, Class<T> tClass , Object ... args) {
PreparedStatement prst=null;
ResultSet rst=null;
List<T> list=null;
int returnint=0;
try {
prst=con.prepareStatement(sql);
int len=args.length;
for (int i = 0; i < len; i++) {
prst.setObject(i+1,args[i]);
}
rst=prst.executeQuery();
ResultSetMetaData rstme= rst.getMetaData();
int columnCount=rstme.getColumnCount();
while (rst.next()) {
T t= tClass.newInstance();
for (int i = 0; i < columnCount; i++) {
String columnName = rstme.getColumnLabel(i + 1);
Field field = tClass.getField(columnName);
field.set(t,rst.getObject(i+1) );
}
list.add(t);
}
return list;
} catch ( Exception throwables) {
throwables.printStackTrace();
}finally {
// 因为连接是传递过来的,所以不在这里关闭连接
MysqlJDBCUtils.closeCon(prst, rst,null);
}
return list;
}
// 但是还是需要想到一个,那就是一些聚合函数,比如GROUP MAX 等 只返回一个特殊值
public <T> T getValue(Connection con,String sql,Class<T> tClass ,Object ... args) {
PreparedStatement prst=null;
ResultSet rst=null;
try {
prst=con.prepareStatement(sql);
int len=args.length;
for (int i = 0; i < len; i++) {
prst.setObject(i+1,args[i]);
}
rst=prst.executeQuery();
if (rst.next()) {
return (T) rst.getObject(1);
}
} catch ( Exception throwables) {
throwables.printStackTrace();
}finally {
// 因为连接是传递过来的,所以不在这里关闭连接
MysqlJDBCUtils.closeCon(prst, rst,null);
}
return null;
}
}
接口定义
package com.test.dao;
import com.test.beans.User;
import java.sql.Connection;
//定义操作用户的接口
public interface UserDAO {
// 插入数据据
void inserData(Connection con, User user);
// 一般创建表的时候,创建一个唯一标识符的值
User getDataByid(Connection con, int id);
// 当然后面还可以有得到全部数据,以及特殊数据等 只为了展现如何使用和概念,不在作其它操作
}
实现某个具体对象操作
package com.test.dao.impl;
import com.test.beans.User;
import com.test.dao.BaseDao;
import com.test.dao.UserDAO;
import java.sql.Connection;
public class UserDAOimpl extends BaseDao implements UserDAO {
@Override
public void inserData(Connection con, User user) {
String sql="INSERT INTO test.user VALUES (?,?, ?)";
// 直接调用父类的方法
updata(con,sql,user.getId(),user.getName(),user.getAddres());
}
@Override
public User getDataByid(Connection con, int id) {
String sql="select id,name,addres from test.user where `id` = ?";
// 直接调用父类的方法
User user= (User) getAllInstance(con,sql,User.class,id);
return user;
}
}
升级
上面虽然可以满足了很多需求,但是为了在UserDAOimpl
类种调用的时候传递了要操作对象的Class,有点琐碎,可以BaseDao
和UserDAOimpl
可以再升级一下:
也就是使用泛型和泛型的反射进行修改
升级后的baseDAO 类
package com.test.dao;
import com.test.util.MysqlJDBCUtils;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.List;
// 无论操作什么数据库,其实有些方法可以提炼处理,然后通用的
// 所以写一个总父类
public class BaseDao<T> {
private Class<T> clazz=null;
// 通过反射得到这个类的Class 这个虽然放在父类中,但是是通过自己调用的所以this值 就是子类本身了
{
Type genericSuperclass = this.getClass().getGenericSuperclass();
ParameterizedType parameterizedType= (ParameterizedType) genericSuperclass;
Type[] types= parameterizedType.getActualTypeArguments();
clazz= (Class<T>) types[0];
}
// 通用的增删改
// 为什么将连接作为一个参数而不是在方法种直接调用工具类得到连接,因为要考虑兼容是否需要使用事务
// 所以在子类种得到Connection
public int updata(Connection con,String sql,Object ... args) {
PreparedStatement prst=null;
int returnint=0;
try {
prst=con.prepareStatement(sql);
int len=args.length;
for (int i = 0; i < len; i++) {
prst.setObject(i+1,args[i]);
}
// executeUpdate 返回影响的行数,如果没有影响返回0
returnint=prst.executeUpdate();
return returnint;
} catch ( Exception throwables) {
throwables.printStackTrace();
}finally {
// 因为连接是传递过来的,所以不在这里关闭连接
MysqlJDBCUtils.closeCon(prst, null,null);
}
return returnint;
}
// 返回一条数据
public T getInstance(Connection con,String sql ,Object ... args) {
PreparedStatement prst=null;
ResultSet rst=null;
int returnint=0;
try {
prst=con.prepareStatement(sql);
int len=args.length;
for (int i = 0; i < len; i++) {
prst.setObject(i+1,args[i]);
}
rst=prst.executeQuery();
ResultSetMetaData rstme= rst.getMetaData();
int columnCount=rstme.getColumnCount();
if (rst.next()) {
T t= clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
String columnName = rstme.getColumnLabel(i + 1);
Field field = clazz.getField(columnName);
field.set(t,rst.getObject(i+1) );
}
return t;
}
} catch ( Exception throwables) {
throwables.printStackTrace();
}finally {
// 因为连接是传递过来的,所以不在这里关闭连接
MysqlJDBCUtils.closeCon(prst, rst,null);
}
return null;
}
// 返回一条数据
public List<T> getAllInstance(Connection con, String sql, Object ... args) {
PreparedStatement prst=null;
ResultSet rst=null;
List<T> list=null;
int returnint=0;
try {
prst=con.prepareStatement(sql);
int len=args.length;
for (int i = 0; i < len; i++) {
prst.setObject(i+1,args[i]);
}
rst=prst.executeQuery();
ResultSetMetaData rstme= rst.getMetaData();
int columnCount=rstme.getColumnCount();
while (rst.next()) {
T t= clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
String columnName = rstme.getColumnLabel(i + 1);
Field field = clazz.getField(columnName);
field.set(t,rst.getObject(i+1) );
}
list.add(t);
}
return list;
} catch ( Exception throwables) {
throwables.printStackTrace();
}finally {
// 因为连接是传递过来的,所以不在这里关闭连接
MysqlJDBCUtils.closeCon(prst, rst,null);
}
return list;
}
// 但是还是需要想到一个,那就是一些聚合函数,比如GROUP MAX 等 只返回一个特殊值
public T getValue(Connection con,String sql ,Object ... args) {
PreparedStatement prst=null;
ResultSet rst=null;
try {
prst=con.prepareStatement(sql);
int len=args.length;
for (int i = 0; i < len; i++) {
prst.setObject(i+1,args[i]);
}
rst=prst.executeQuery();
if (rst.next()) {
return (T) rst.getObject(1);
}
} catch ( Exception throwables) {
throwables.printStackTrace();
}finally {
// 因为连接是传递过来的,所以不在这里关闭连接
MysqlJDBCUtils.closeCon(prst, rst,null);
}
return null;
}
}
升级后的UserDAOimpl
package com.test.dao.impl;
import com.test.beans.User;
import com.test.dao.BaseDao;
import com.test.dao.UserDAO;
import java.sql.Connection;
public class UserDAOimpl extends BaseDao<User> implements UserDAO {
@Override
public void inserData(Connection con, User user) {
String sql="INSERT INTO test.user VALUES (?,?, ?)";
// 直接调用父类的方法
updata(con,sql,user.getId(),user.getName(),user.getAddres());
}
@Override
public User getDataByid(Connection con, int id) {
String sql="select id,name,addres from test.user where `id` = ?";
// 直接调用父类的方法
User user= (User) getAllInstance(con,sql,id);
return user;
}
}
这个地方也看出了反射在框架中的作用了,本篇就是简单走Dao而已,大家理解一下。