请选择 进入手机版 | 继续访问电脑版

JDBC_CRUD 操作 - 装逼版

发表于 2016-08-13 17:20 显示全部楼层 19 522

继续上篇JDBC_CRUD 操作 - 实用版

不是上一篇的优化,而是另外一种方式,有点恶心,用来装逼的。

包结构

blob.png

package com.langfei._05_.util;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * jdbc抽取,
 * 1、共用了获取数据库连接方式
 * 2、共用了数据库资源关闭方式
 * 3、使用properties 方式获取数据连接信息.
 * @author yexingfei
 */
public class JdbcUtil {
	private static String username;
	private static String password;
	private static String url;

	private JdbcUtil() {
	}
	static {
		InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties");
		Properties properties = new Properties();
		try {
			properties.load(inputStream);
			username = properties.getProperty("username");
			password = properties.getProperty("password");
			url = properties.getProperty("url");
			Class.forName(properties.getProperty("driver"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static Connection getConn() {
		try {
			return DriverManager.getConnection(url, username, password);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void close(Connection connection, Statement ps, ResultSet resultSet) {
		try {
			if (connection != null) {
				connection.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if (ps != null) {
				ps.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if (resultSet != null) {
				resultSet.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

}
package com.langfei._05_.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 字段(列)注解,用于标识列的名字
 * 如果某个字段 没有标有这个注解,则列名默认为字段名
 * @author yexingfei
 *
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	String value();
}
package com.langfei._05_.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ID {

}
package com.langfei._05_.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 表注解,用于标识表的名字
 * 如果某个domain 没有标有这个注解,则表名默认为domain 类名
 * @author yexingfei
 *
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
	String value();
}
package com.langfei._05_.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.langfei._05_.annotation.ID;
import com.langfei._05_.annotation.Column;
import com.langfei._05_.annotation.Table;
import com.langfei._05_.domain.Student;
import com.langfei._05_.handler.IResultSetHandler;


public class JdbcTemplate {
	//sql 的条件 eg: xx=YY
	private static List<String> conditions = new ArrayList<>();
	private JdbcTemplate(){}

	//通过字节码获取sql
	private static <T> Map<String, Object> getSqlAndValue(String oper, Class<T> t) {
		try {
			return getSqlAndValue(oper, t.newInstance());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	//通过对象获取sql
	private static <T> Map<String, Object> getSqlAndValue(String oper, T t) {
		Map<String, Object> map = new HashMap<>();
		
		Class<?> clzz = t.getClass();
		// ①:获取表名
		String tableName = clzz.getSimpleName();
		// 如果标有Table注解,则使用注解上的值
		if (clzz.isAnnotationPresent(Table.class)) {
			Table table = clzz.getAnnotation(Table.class);
			tableName = table.value();
		}
		
		// 1:拼接sql
		StringBuilder columns = new StringBuilder();  //列列表
		StringBuilder values = new StringBuilder();  //占位符
		
		//当oper 为update 时,使用这个拼接
		StringBuilder sqlUpdate = new StringBuilder();

		// ②:获取列与值的占位符?
		// ③:获取?对应的值
		List<Object> params = new ArrayList<>();
		
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(clzz, Object.class);
			PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor pd : pds) {
				
				//列列表跟占位符? 可分3种处理:
				//1、selete 的列列表需要 id,格式 xx, xx, xx,且不需要占位符  
				//2、insert 的列列表不需要id,格式 xx, xx, xx, 且需要占位符 
				String column = "";
				Field field = clzz.getDeclaredField(pd.getName());
				// 如果是id 则跳过,默认的id是自动增长
				if (field.isAnnotationPresent(ID.class) &&  !"select".equalsIgnoreCase(oper)) {
					continue;
				}
				// 如果字段中标有Column字段,则使用标记的列名,反之使用默认的字段名
				if (field.isAnnotationPresent(Column.class)) {
					Column jField = field.getAnnotation(Column.class);
					column = jField.value();
				} else {
					Column jField = field.getAnnotation(Column.class);
					column = pd.getName();
				}
				columns.append(column + ",");
				values.append("?,");
				params.add(pd.getReadMethod().invoke(t));
				
				//3、update 的列表需要特殊处理格式  xxx = ?
				if("update".equalsIgnoreCase(oper)){
					sqlUpdate.append(column + "=" + "?,");
				}
			}
			// 去掉最后一个 ,
			columns.deleteCharAt(columns.length() - 1);
			values.deleteCharAt(values.length() - 1);
			String sql = "";
			if("select".equalsIgnoreCase(oper)){
				sql = "SELECT " + columns + " FROM " + tableName +" ";
				params = null;
			}else if("insert".equalsIgnoreCase(oper)){
				sql = "INSERT INTO " + tableName + " (" + columns +") "
						+ " VALUES( " + values + ") ";
			}else if("update".equalsIgnoreCase(oper)){
				sqlUpdate.deleteCharAt(sqlUpdate.length() - 1);
				sql = "UPDATE " + tableName + " SET " + sqlUpdate;
			}else if("delete".equalsIgnoreCase(oper)){
				sql = "DELETE FROM " + tableName;
				params = null;
			}
			map.put("sql", sql);
			map.put("params", params);
			return map;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}
	
	
	/**
	 * 设置条件
	 * @param 条件值
	 */
	public static void addCondition(String condis) {
		conditions.add(condis);
	}
	//拼接where 条件, 这里待完善
	private static String getWhereSql(){
		StringBuilder sql = new StringBuilder(" WHERE 1 = 1 ");
		//此处只允许and 
		if(!conditions.isEmpty()){
			for(String str : conditions){
				sql.append(" and " + str);
			}
		}
		conditions.clear();
		return sql.toString();
	}

	
	/**
	 * @param sql  使用预编译DML语句(update、insert、delete)
	 * @param params sql中占位符?对应的参数,需要按顺序
	 * @return
	 */
	private static int update(String sql, Object...params){
		System.out.println(sql);
		Connection connection = JdbcUtil.getConn();
		PreparedStatement preparedStatement = null;
		try {
			preparedStatement = connection.prepareStatement(sql);
			for(int i = 0; i < params.length; i++){
				preparedStatement.setObject(i+1, params[i]);
			}
			return preparedStatement.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JdbcUtil.close(connection, preparedStatement, null);
		}
		return -1;
	}
	
	/**
	 * @param sql  使用预编译DML语句(SELETE)
	 * @param params sql中占位符?对应的参数,需要按顺序
	 * @return T 处理resultSet 返回的数据
	 */
	private static <T> T query(String sql, IResultSetHandler<T> handler,  Object... params){
		Connection connection = JdbcUtil.getConn();
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		try {
			preparedStatement = connection.prepareStatement(sql);
			for(int i = 0; i < params.length; i++){
				preparedStatement.setObject(i+1, params[i]);
			}
			resultSet = preparedStatement.executeQuery();
			//让处理逻辑下放到调用者实现
			return handler.handler(resultSet);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JdbcUtil.close(connection, preparedStatement, resultSet);
		}
		return null;
	}

	//添加
	public static void add(Student student) {
		Map<String, Object> map = getSqlAndValue("insert", student);
		String sql = (String) map.get("sql");
		List<Object> params = (List<Object>) map.get("params");
		JdbcTemplate.update(sql, params.toArray());
	}

	//删除
	public static <T> int delete(Class<T> t) {
		Map<String, Object> map = getSqlAndValue("DELETE", t);
		String sql = (String) map.get("sql") + getWhereSql();
		return JdbcTemplate.update(sql, new Object[]{});
	}

	//更新
	public static <T> int update(T t) {
		Map<String, Object> map = getSqlAndValue("update", t);
		String sql = (String) map.get("sql") + getWhereSql();
		List<Object> params = (List<Object>) map.get("params");
		return JdbcTemplate.update(sql, params.toArray());
	}
	
	//查询
	public static <T, E> T query(Class<E> e, IResultSetHandler<T> handler) {
		Map<String, Object> map = getSqlAndValue("select", e);
		String sql = (String) map.get("sql") + getWhereSql();
		System.out.println(sql);
		return JdbcTemplate.query(sql, handler);
	}
}
package com.langfei._05_.domain;

import com.langfei._05_.annotation.ID;
import com.langfei._05_.annotation.Table;

//数据对象Student
@Table("t_student")
public class Student {
	@ID
	private Long id;
	private String name;
	private String gender;
	private Integer age;
	private String address;
	private String clzz;
	
	public Student() {
	}
	
	public Student(Long id){
		this.id = id;
	}
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getClzz() {
		return clzz;
	}
	public void setClzz(String clzz) {
		this.clzz = clzz;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", address=" + address
				+ ", clzz=" + clzz + "]";
	}
}
package com.langfei._05_.dao;

import java.util.List;

import com.langfei._05_.domain.Student;

/**
 * student DAO 接口规范,规定student crud操作 
 * @author yexingfei
 */
public interface IStudentDAO {
	void add(Student student);
	int delete(Long id);
	int update(Student student);
	Student find(Long id);
	List<Student> findAll();
}
package com.langfei._05_.handler;

import java.sql.ResultSet;

/**
 * ResultSetHander 接口,专门用于处理Resultset
 * 处理Resultset 之后返回什么类型由调用者决定
 * @author yexingfei
 */
public interface IResultSetHandler<T> {
	T handler(ResultSet resultSet);
}
package com.langfei._05_.dao.impl;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import com.langfei._05_.dao.IStudentDAO;
import com.langfei._05_.domain.Student;
import com.langfei._05_.handler.IResultSetHandler;
import com.langfei._05_.util.JdbcTemplate;


public class StudentDAOImpl implements IStudentDAO {

	@Override
	public void add(Student student) {
		JdbcTemplate.add(student);
	}

	@Override
	public int delete(Long id) {
		//待完善
		JdbcTemplate.addCondition("id="+ id);
		return JdbcTemplate.delete(Student.class);
	}

	@Override
	public int update(Student student) {
		JdbcTemplate.addCondition("id="+ student.getId());
		return JdbcTemplate.update(student);
	}

	@Override
	public Student find(Long id) {
		JdbcTemplate.addCondition("id="+ id);
		// 通过id去查跟查询全部区别:一个返回1条数据, 一个可能返回多个数据
		// 使用匿名内部类,处理返回的ResultSet
		// 传入的泛型是Student 返回结果是Student 对象
		return JdbcTemplate.query(Student.class, new IResultSetHandler<Student>() {
			@Override
			public Student handler(ResultSet resultSet) {
				Student student = null;
				try {
					if (resultSet.next()) {
						student = new Student();
						student.setAddress(resultSet.getString("address"));
						student.setAge(resultSet.getInt("age"));
						student.setName(resultSet.getString("name"));
						student.setClzz(resultSet.getString("clzz"));
						student.setGender(resultSet.getString("gender"));
						student.setId(resultSet.getLong("id"));
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				return student;
			}
		});
	}

	@Override
	public List<Student> findAll() {
		return JdbcTemplate.query(Student.class, new IResultSetHandler<List<Student>>() {
			@Override
			public List<Student> handler(ResultSet resultSet) {
				List<Student> list = new ArrayList<>();
				Student student = null;
				try {
					while (resultSet.next()) {
						student = new Student();
						student.setAddress(resultSet.getString("address"));
						student.setAge(resultSet.getInt("age"));
						student.setName(resultSet.getString("name"));
						student.setClzz(resultSet.getString("clzz"));
						student.setGender(resultSet.getString("gender"));
						student.setId(resultSet.getLong("id"));
						list.add(student);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				return list;
			}
		});
	}
}
package com.langfei._05_.test;

import java.util.List;

import org.junit.Test;

import com.langfei._05_.dao.IStudentDAO;
import com.langfei._05_.dao.impl.StudentDAOImpl;
import com.langfei._05_.domain.Student;

public class StudentDAOTest {

	private IStudentDAO dao = new StudentDAOImpl();
	@Test
	public void testAdd() throws Exception {
		Student student = new Student();
		student.setAddress("广东");
		student.setAge(10);
		student.setClzz("大神1班");
		student.setGender("仔");
		student.setName("飞");
		dao.add(student);
	}
	@Test
	public void testDelete() throws Exception {
		Long id = 7L;
		dao.delete(id);
	}
	@Test
	public void testUpdate() throws Exception {
		Student student = new Student();
		student.setId(8L);
		student.setAddress("广东1");
		student.setAge(12);
		student.setClzz("大神2班");
		student.setGender("妞");
		student.setName("大飞");
		dao.update(student);
	}
	@Test
	public void testFind() throws Exception{
		Student student = dao.find(5L);
		System.out.println(student);
	}
	
	@Test
	public void testFindAll() throws Exception{
		List<Student> list = dao.findAll();
		for(Student student : list){
			System.out.println(student);
		}
	}
}

总结:

这个版本使用了内省,注解,泛型相关知识,通过注解配置拼接sql,但存在一个硬伤,where 条件语句时,变化太多,需要考虑很多场景,此处仅用演示,没有深入研究,大家看看就好。

回复 使用道具
举报
华盛顿哈

发表于 2017-04-30 00:41 显示全部楼层

system.out.println("大神66的");


回复 支持 反对 使用道具
举报
华盛顿哈

发表于 2017-04-30 00:39 显示全部楼层

大神,你好

回复 支持 反对 使用道具
举报
山秀

发表于 2017-02-18 11:31 显示全部楼层

别人说是金子总要发光的,我就来看看。

回复 支持 反对 使用道具
举报
nettman

发表于 2017-02-18 10:45 显示全部楼层

回复 支持 反对 使用道具
举报
烟雨过客

发表于 2017-02-17 22:08 显示全部楼层

以诚感人者,人亦诚而应。一点回复,敬请笑纳!

回复 支持 反对 使用道具
举报
晴天屁屁

发表于 2017-02-17 18:54 显示全部楼层

回复 支持 反对 使用道具
举报
凌大胖纸

发表于 2017-02-17 12:23 显示全部楼层

回复 支持 反对 使用道具
举报
做个有钱银

发表于 2017-02-17 10:01 显示全部楼层

回复 支持 反对 使用道具
举报
目定口呆

发表于 2017-02-16 01:16 显示全部楼层

回复 支持 反对 使用道具
举报
12下一页

发表新文章
叶星飞

小码哥骨干成员

0

学分

968

学币

1059

积分

小码哥骨干成员

Rank: 6Rank: 6

积分
1059
Ta的主页 发消息
精华帖排行榜

精彩推荐

  • 关注小码哥教育