ORM基本思想
当我们接触到数据库和Java连接的内容时,不得不提到的一点就是ORM(Object Relational Mapping)思想,翻译过来就是对象关系映射,简单来说就是表结构中的字段和类中的属性对应映射,实现一条数据库记录对应一个JavaBean对象
添加數據的封装
现在我们封装一个方法,使得我们传入一个对象实参之后,对应的数据库可以对应的增加一条数据
假设,我们有一个Trolley购物车类和AddUtil类
public class Trolley {
private int productID;
private int quantity;
public Trolley(int productID, int quantity) {
super();
this.productID = productID;
this.quantity = quantity;
}
public int getProductID() {
return productID;
}
public void setProductID(int productID) {
this.productID = productID;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
public class AddUtil {
//过滤方法为methodName的方法并放入List容器
private static List<Method> getMatchedMethods(Object obj, String methodName) {
Method[] methods = obj.getClass().getDeclaredMethods();
List <Method> list = new ArrayList<>();
for (int index = 0; index < methods.length; index++) {
if (methods[index].getName().indexOf(methodName) != -1) {
//Class returnType = methods[index].getReturnType();
list.add(methods[index]);
}
}
return list;
}
public static <T> void addData(T obj) {
Connection conn = JDBCUtil.getConnection();
//假设现在需要插入String sql = "insert into trolley(md_mid,trolley_quantity) values (..,..,..)";
Map<String, Object> map = new HashMap<>();
Set<String> methodName = new HashSet<>();//用于存储方法的名称
Class clz = obj.getClass();
StringBuffer sql = new StringBuffer("insert into ");
sql.append(clz.getSimpleName().toLowerCase());
sql.append("(");
List<Method> methodList = getMatchedMethods(obj, "get");
Iterator<Method> it = methodList.iterator();
while(it.hasNext()) {
Method method = it.next();
String attribute = method.getName().substring(3).toLowerCase();//从方法中获取属性名称
try {
System.out.println(method.getName());
Object value = method.invoke(obj);
System.out.println(value);
map.put(attribute,value);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
sql.append(attribute);
sql.append(",");
}
sql.setCharAt(sql.lastIndexOf(","), ')');//实现了这一部分insert into trolley(md_mid,trolley_quantity)
sql.append("values(");
List<Method> methodList2 = getMatchedMethods(obj, "get");
Iterator<Method> it2 = methodList2.iterator();
while(it2.hasNext()) {
Method method = it2.next();
String attribute = method.getName().substring(3).toLowerCase();//从方法中获取属性名称
Object value = map.get(attribute);
sql.append(value);
sql.append(",");
}
sql.setCharAt(sql.lastIndexOf(","), ')');
try {
PreparedStatement ps = conn.prepareStatement(sql.toString());
System.out.println(sql.toString());
ps.executeUpdate();
JDBCUtil.realse(conn, ps);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Trolley t = new Trolley(1100, 500);
addData(t);
}
}
但是细心的朋友发现,以上通过反射获取对象的get方法,并拆解get方法的全称,得到字段名(例如setProductID拆解之后可以获取ProductID字段),然后通过get方法获取属性的属性值也就是对应的数据库里面的字段值。
最后通过SQL语句将数据传输到数据库中。
但是上述方法有一个缺陷,就是我们的数据库的字段名称和Javabean类的属性值要一一对应才能实现对象到数据库的添加。当然我们也有相应的应对措施,例如约定一个规范,打个比方,类中的属性可以叫做 ProductID,
那么数据库中的字段名称可以命名为trolley_productid,或者product_id,这样我们可以新建一个方法,将类的属性名转为数据库的字段名称来进行调用。
但是!!最终极的方法是采用我们的==注解==方式,我们可以先定义一个注解来对这个Trolley类的属性做约束,并命名(类似于数据库的起别名)。(友情提示:如果对注解还不太熟的小伙伴可以先看我的另一篇讲解注解的文章 Marco’s Java 之【Annotation注解】)
@Target(value=ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value() default "";
}
其次,我们可以将该注解放到我们需要注解的属性上方并命名
public class Trolley {
@Column(value="md_mid")
private int productID;
@Column(value="trolley_quantity")
private int quantity;
public Trolley(int productID, int quantity) {
super();
this.productID = productID;
this.quantity = quantity;
}
public int getProductID() {
return productID;
}
public void setProductID(int productID) {
this.productID = productID;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
最后还是建一个AddUtil类封装相应的Add方法,将内容进行大换血!
public class AddUtil {
//通过该方法获取该对象的注解value,以及这个属性的值
private static Map<String,Object> getAnnotations(Object obj) {
Map<String,Object> map = new HashMap<>();
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field field : declaredFields) {
Column anno = field.getAnnotation(Column.class);
if(anno!=null){
String attribute = anno.value();
try {
field.setAccessible(true);
Object value = field.get(obj);
map.put(attribute, value);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return map;
}
public static <T> void addData(T obj) {
Connection conn = JDBCUtil.getConnection();
Map<String, Object> map = getAnnotations(obj);
StringBuffer sql = new StringBuffer("insert into ");
Class clz = obj.getClass();
sql.append(clz.getSimpleName().toLowerCase());
sql.append("(");
Set entryset = map.entrySet();
Iterator<Entry<String,Object>> it = entryset.iterator();
while(it.hasNext()) {
Entry<String,Object> entry = it.next();
String attribute = entry.getKey();
sql.append(attribute);
sql.append(",");
}
sql.setCharAt(sql.lastIndexOf(","), ')');//实现了这一部分insert into trolley(md_mid,trolley_quantity)
sql.append("values(");
Set entryset2 = map.entrySet();
Iterator<Entry<String,Object>> it2 = entryset2.iterator();
while(it2.hasNext()) {
Entry<String,Object> entry = it2.next();
Object value = entry.getValue();
sql.append(value);
sql.append(",");
}
sql.setCharAt(sql.lastIndexOf(","), ')');//实现了这一部分insert into trolley(md_mid,trolley_quantity)
try {
PreparedStatement ps = conn.prepareStatement(sql.toString());
ps.executeUpdate();
JDBCUtil.realse(conn, ps);
} catch (SQLException e) {
e.printStackTrace();
}
public static void main(String[] args) {
Trolley t = new Trolley(1100, 500);
addData(t);
}
}
查詢數據的封装
实际开发中,我们可能会需要查询这一个数据库中的多个表,并且将表中的数据导出来==。
那么我们可以通过将查询的内容进行封装,在Java中创建一个实体类让类中的属性和数据库中的字段映射起来
public class ResultMetaTest{
public static <T> List<T> queryData(Class<T> clz, String sql, Object...param) {
Connection conn = JDBCUtil.getConnection();//创建连接对象
try {
PreparedStatement ps = conn.prepareStatement(sql);//创建操作数据库对象
//设置条件判断中的值
for(int i = 0; i < param.length; i++) {
ps.setObject(i+1, param[i]);
}
ResultSet rs = ps.executeQuery();//获取结果集对象
ResultSetMetaData meta = rs.getMetaData();//获取数据集元信息
int column = meta.getColumnCount();//获取所搜寻的字段个数或者列数
List<T> list = new ArrayList<>();//创建用于储存构建出来的对象的容器
while(rs.next()) {
Map<String,Object> map = new HashMap<>();//创建用于储存保存类的属性的map集合
for(int i = 0; i < column; i++) {
String columnName = meta.getColumnLabel(i+1);//得到每一列的或者每一个字段的名称
Object obj = rs.getObject(columnName);//根据字段名称获取每一行对应的字段值
map.put(columnName, obj);
}
if(!map.isEmpty()) {
T obj = clz.newInstance();//通过传入的类的Class对象创建这个类的对象
Set <Entry <String,Object>> entryset = map.entrySet();
for (Entry<String, Object> entry : entryset) {
String atribute = entry.getKey();//提取这个类中的属性名称
Object value = entry.getValue();//提取这个类中属性的值
Field attribute = clz.getDeclaredField(atribute);
attribute.setAccessible(true);//注意要设置权限为开放
attribute.set(obj, value);//通过反射给对象赋值
}
list.add(obj);//将赋值完成的对象放入ArrayList容器中
}
}
JDBCUtil.realse(conn, ps, rs);//释放资源
return list;
} catch (SQLException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception {
String sql = "select u_uname as userName,u_pwd as password,"
+ "u_tele as telePhone,u_realname as realName from userinfo where u_id = ?";
List<User> list = queryData(User.class,sql,1);
System.out.println(list);
}
}