基于JDBC封装数据库基本CURD操作

 在使用jdbc时,我们每进行一次数据库操作,都会建立连接 关闭连接 如果是查询操作我们每次都会获得结果集并对它进行遍历输出结果 如果是更新操作那么我们也得重复写着可能就几个参数不一样的更新语句.这就导致了我们代码冗余度非常高,并且可复用性很差 . 这个时候我们就可以考虑对这些数据库常规操作封装成一个工具类,这样我们以后如果要对数据库进行常规操作就可以直接调用这个工具类的方法,而不需要我们每次操作都要重复把一个代码写很多遍,话不多说,马上开始讲解如何封装

1.准备属性文件: 在src目录下创建一个新的file文件,用jdbc.properties命名 然后用键值对的形式写出驱动类路径,url地址,数据库用户名,用户密码,连接池最长等待时间,初始连接个数,最大同时使用的连接数(这里使用数据库连接池技术,减少时间消耗)

2.

public static void init(){
if(ds==null || ds.isClosed()){
new DruidDataSource();
}
try {
Class.forName(DRIVER_CLASS); //mysqljdbc4之后可以不用手动加载驱动路径,获取连接的时候能够自动加载
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
ds.setDriverClassName(DRIVER_CLASS);
ds.setUrl(URL);
ds.setUsername(USER);
ds.setPassword(PASSWORD);
ds.setMaxActive(MAX_ACTIVE);
ds.setInitialSize(INIT_SIZE);
ds.setMaxWait(MAX_WAIT);
}
对连接池对象进行初始化操作


3.返回连接对象
public static synchronized Connection getConn() {
try {
if(ds==null || ds.isClosed()){
init();
}
return ds.getConnection();
} catch (SQLException e){
e.printStackTrace();
}
return null;
}
这里为了防止多线程获得连接对象造成多个线程公用一个连接对象,使用synchronized关键字修饰方法


4.关闭连接
public static void close(ResultSet rs,Statement stat,Connection conn){

try {
if(rs != null) rs.close();
if(stat != null)stat.close();
if(conn != null)conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
第二个参数使用 Statement接口,增加参数多态性


5.更新操作封装(添加,删除,更改)
public static boolean exeUpdate( Connection conn, String sql,Object...params){


PreparedStatement ps = null;
try {
ps = conn.prepareStatement(sql);
if(params != null){
for (int i = 0; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
}
return ps.executeUpdate()>0;

} catch (SQLException e) {
e.printStackTrace();
}finally{
close(null, ps, conn);
}

return false;
}
用户传进来三个参数,一个是连接对象,一个是sql语句,一个是动态参数数组(注意:动态参数数组必须放到参数列表末尾,里面放置sql语句预处理需要使用到的参数值)

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在封装查询操作前,我们还要做一些准备工作. 1.因为查询得到的结果集是类似map集合的键值对结果,我们不妨定义一个把键值对转化为map集合的方法,(注意:表中一条数据就是一个map
集合,因为map集合的键不允许重复,所以我们有必要定义一个以map集合为泛型的List集合,最后再将这个集合返回,如此,我们便拿到了这个表中的所有记录)2.查询操作最后返回的肯定是对应实体类的对象(一条)或者对象数组(多条),所以我们还得定义一个将map集合转换为对应实体类对象的方法.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6.执行相关查询操作,返回一个List<Map<String,Object>>集合
public static List<Map<String,Object>> queryMaps(String sql,Object...params){
List<Map<String,Object>> list = new ArrayList<>();
PreparedStatement ps = null;
Connection conn = null;
ResultSet rs = null;
conn = getConn();
try {
ps = conn.prepareStatement(sql);

if(params != null){
for (int i = 0; i < params.length; i++) {
//对ps进行预处理
ps.setObject(i+1, params[i]);
}
}

//取到结果集

rs = ps.executeQuery();
//获取结果集的元数据对象ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
//获取总列数
int columnCount = rsmd.getColumnCount();
//遍历结果集
while(rs.next()){
//定义一个map,用于装数据
Map<String,Object> map = new HashMap<String, Object>();
//遍历获取每一列的信息
for (int i = 1; i <= columnCount; i++) {
//获取列名称,作为map集合的键
String key = rsmd.getColumnName(i);
//获取列标签(用于取得列表中的值,因为并不知道用户有没有设置别名 所以统一用label)
String label = rsmd.getColumnLabel(i);
//获得列值
Object value = rs.getObject(label);
if(Objects.nonNull(value))
map.put(key, value);
}
list.add(map);
}
这里用到了元数据处理相关知识,大家可以看看代码上的注释,解释的挺详细

7.将map集合转换成对应实体类的对象
public static <T> T mapToBean(Map<String,Object>map,Class<T> t){
T obj = null;
try {
//根据我们提供的类型,我们创建一个对应的对象
obj = t.newInstance();
//获取Class中所有属性字段
Field[] fields = t.getDeclaredFields();
//遍历获取每一个对象
for (Field f : fields) {
String fname = f.getName();
//获取属性值
Object value = map.get(fname);
if(f != null){
//设置属性对象的可访问性
f.setAccessible(true);
//设置值
f.set(obj, value);
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}



return obj;
}
这里主要运用到了反射的知识,先用传进来的Class对象构建一个新的实体类对象 然后取得该对象所有的属性的集合,对该集合遍历,获得其中属性的属性名当做map集合的键值,之后通过通过键值获得map集合的值value,然后将所有属性设置为可访问f.setAccessible(true)
,最后使用field中的set(obj,value)方法将map集合中的值传入变量的属性中并返回该对象

------------------------------------------
这两个方法定义完成后,我们就可以定义我们的查询方法了
------------------------------------------

8.查询一条数据
public static<T> T queryOne(Class<T> t,String sql,Object...params){
List<Map<String,Object>> list = queryMaps(sql, params);
if(list.size() > 0) {

Map<String,Object> map = list.get(0);
return mapToBean(map, t);

}

return null;
}
9.查询多条数据public static<T> List<T> queryList(Class<T> t,String sql,Object...param){
   List<T> list = new ArrayList<T>();
List<Map<String,Object>> maps = queryMaps(sql,param);
//遍历集合中每一条数据(map)
maps.forEach(m->{
//将javabean装入list
T obj = mapToBean(m, t);
list.add(obj);
});

return list;
}
和查询单条数据差不多,就是多了一个遍历的过程

9.查询数据总条数
public static int queryCount(String sql,Object...params) throws SQLException {

Connection conn = getConn();
PreparedStatement ps = conn.prepareStatement(sql);
/**如果有动态参数数组的话就要对sql进行预处理*/
if(params != null){
for (int i = 0; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
}
/**没有的话,直接执行查询语句就行了*/
ResultSet rs = ps.executeQuery();
if(rs.next()){
return rs.getInt(1);

}else{

return 0;

}
}

注意这里指针一定要往下移动一位,不然rs.get(1)取不到值
到此,这个封装工具类就完成了 下次我们如果要使用数据库的相关操作可以直接调用此类方法 只需修改它的属性文件就行了

今天你学到东西了吗
 
原文地址:https://www.cnblogs.com/j-1-z-2-s-3/p/13457752.html