通过对JDBC操作数据库的学习,我们会发现,由于JDBC操作数据库的步骤基本没有大的变化,针对所有的数据访问操作,都会存在大量重复代码,因此,对操作数据库的步骤封装就显得十分有必要了,如下:
为了不用修改java源代码,可以将连接数据库的常见字符串直接配置到properties文件中:
在项目的src根目录下新建一个jdbc.properties文件。
文件内容:
#mysql connection config
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mydb
user=root
password=123456
maxActive=10
minIdle=1
maxWait=10000
DAO(Data Access Object):数据访问对象,在实际开发中由于项目的结构复杂,一般会项目进行分层实现,常见的MVC模式为:Model、View、Controller等三层,而对数据的访问操作一般位于Model层,称之为数据模型,因此对操作数据的步骤一般也会在一个特定的位置一并处理,这一层我们称之为DAO层,该层为直接访问数据库,执行相关表的CRUD操作,不参与任何业务逻辑的实现,只负责操作数据库表中的数
由于数据库连接是一种资源,这种资源在使用前必须先创建,而这个创建过程是存在时间和空间的开销的,如果每次在执行数据库访问时都创建连接,并且使用完后要关闭连接,这个过程必然是效率低下的;因此,在实际开发中可以考虑在进行数据库操作前,先提前创建并维护一批数据库连接对象,当需要使用时,从这批对象中获取一个连接,用完之后再返还,从而避免了不必要的时间开销,提高程序的运行效率,这种技术在JDBC中称之为连接池技术(Connection Pool)。
Druid连接池使用前先导入Druid的依赖:druid-1.1.9.jar(或者其他版本)
反射是java中类的一种自省机制,通过反射可以在运行时获取类中的成分,并且使用,从而提高了java的动态性;java中任何一个类都有一个对应的java.lang.Class对象,这个对象包含了类中的所有成分(属性,构造器,方法,注解等)
基于以上等多个知识对数据库操作进行封装
public class DBUtils {
public static String driverClass;
public static String url;
public static String user;
public static String password;
public static int maxActive;
public static int minIdle;
public static long maxWait;
private static DruidDataSource dataSource;
static{
init();
}
public static void init(){
try {
Properties prop=new Properties();
InputStream is=DBUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
prop.load(is);
driverClass=prop.getProperty("driverClass");
url=prop.getProperty("url");
user=prop.getProperty("user");
password=prop.getProperty("password");
maxActive=Integer.parseInt(prop.getProperty("maxActive"));
minIdle=Integer.parseInt(prop.getProperty("minIdle"));
maxWait=Long.parseLong(prop.getProperty("maxWait"));
dataSource=new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
dataSource.setMaxActive(maxActive);
dataSource.setMinIdle(minIdle);
dataSource.setMaxWait(maxWait);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static synchronized Connection getConn() {
if(dataSource==null||dataSource.isClosed()){
init();
}
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void close(ResultSet rs,Statement stat,Connection conn){
if(dataSource!=null){
dataSource.close();
}
}
//封装增删改操作
public static int exeUpdate(String sql,Connection conn,Object... params){
PreparedStatement ps=null;
try {
ps=conn.prepareStatement(sql);
if(Objects.nonNull(params)){
for(int i=0;i<params.length;i++){
ps.setObject(i+1, params[i]);
}
}
int i=ps.executeUpdate();
return i;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
close(null,ps,null);
}
return 0;
}
public static <T> List<T> query(String sql,CallBack callback,Object... params){
List list=null;
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=getConn();
ps=conn.prepareStatement(sql);
if(Objects.nonNull(params)){
for(int i=0;i<params.length;i++){
ps.setObject(i+1, params[i]);
}
}
rs=ps.executeQuery();
list=callback.call(rs);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
close(rs,ps,conn);
}
return list;
}
//内部接口,里面包含一个函数
public interface CallBack{
List call(ResultSet rs) throws SQLException;
}
//封装通用的查询集合操作,对任何形式的查询,都能返回一个集合对象
//t:需要返回的数据类型
//sql:查询目标语句
//params:执行查询所需的参数
//返回指定对象
public static <T> List<T> queryList(Class<T> t,String sql,Object... params){
//声明空集合
List<T> data=new ArrayList<>();
//获取查询结果信息
List<Map<String,Object>> list=getDataPair(sql,params);
if(list.isEmpty()){
return data;
}
for(Map<String,Object> map:list){
T obj=parseMapToBean(map,t);
data.add(obj);
}
return data;
}
//封装通用的查询对象操作,对任何形式的查询,都能返回一个确定的对象
public static <T> T queryOne(Class<T> t,String sql,Object... params){
List<Map<String,Object>> list=getDataPair(sql,params);
if(!list.isEmpty()){
Map<String,Object> map=list.get(0);
T obj=parseMapToBean(map,t);
return obj;
}
return null;
}
//将一个map集合对象转换为javaBean并返回
private static <T>T parseMapToBean(Map<String, Object> map, Class<T> t) {
T obj=null;
try {
//创建一个空实例
obj=t.newInstance();
//获取map集合的键集(所以列名称,即要返回对象的属性名)
Set<String> keys=map.keySet();
for(String cname:keys){
//获取属性对象
Field f=t.getDeclaredField(cname);
//获取set方法名称
String setMethodName="set"+cname.substring(0,1).toUpperCase()+cname.substring(1);
//获取set方法对象
Method method=t.getMethod(setMethodName, f.getType());
//执行方法
method.invoke(obj, map.get(cname));
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
private static List<Map<String,Object>> getDataPair(String sql,Object... params){
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
List<Map<String,Object>> list=new ArrayList<>();
try {
conn=getConn();
ps=conn.prepareStatement(sql);
if(Objects.nonNull(params)){
for(int i=0;i<params.length;i++){
ps.setObject(i+1, params[i]);
}
}
rs=ps.executeQuery();
//获取结果集元数据
ResultSetMetaData rsmd=rs.getMetaData();
//获取列总数,列名称,获取标签名,获取列值,将相关数据存储到map集合
//获取总列数
int count=rsmd.getColumnCount();
while(rs.next()){
//对结果集每遍历一次,获取一条数据
Map<String,Object> map=new HashMap<>();
//遍历每一列
for(int i=1;i<=count;i++){
//获取列名称
String columnName=rsmd.getColumnName(i);
//获取标签名(别名)
String columnLabel=rsmd.getColumnLabel(i);
//获取列值
Object value=rs.getObject(columnLabel);
if(Objects.nonNull(value)){
//将数据存入map
map.put(columnName, value);
}
}
//将map集合存入List
list.add(map);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
DBUtils.close(rs, ps, conn);
}
return list;
}
}
导入该工具类后可以将对数据库的增删查改操作简化:
public boolean insert(Student stu) {
String sql="insert into student(sname,sex,age,birthday) values(?,?,?,?)";
int i=DBUtils.exeUpdate(sql, conn, stu.getSname(),stu.getSex(),stu.getAge(),stu.getBirthday());
return i>0;
}
public boolean update(Student stu) {
String sql="update student set age=? where sname=?";
int i=DBUtils.exeUpdate(sql, conn, stu.getAge(),stu.getSname());
return i>0;
}
public boolean delete(int id) {
String sql="delete from student where id=?";
int i=DBUtils.exeUpdate(sql, conn, id);
return i>0;
}
public List<Student> findAll() {
String sql="select *from student";
return DBUtils.queryList(Student.class, sql);
}
public Student findOne(int id) {
String sql="select *from student where id=?";
return DBUtils.queryOne(Student.class, sql,id);
}