使用反射及Annotation自定义Dao组件
来源:互联网 发布:java输出99乘法表对齐 编辑:程序博客网 时间:2024/05/24 03:25
引言
目前的持久化O/R框架很多,包括Hibernate,Mybats和JPA等,同时还有Apache的DBUtil组件等,通过使用这些框架,程序员避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。这些框架都可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。这些框架使用的技术主要用反射机制,Annotation,XML等,为了更好的理解持久层框架的实现原理,下面通过反射和Annotation来手动实现一个持久化的组件;
1.使用技术
annotation:自定义Annotation,用来定义两个注解,@Table用来说明VO对应的表名,如果列名与类名相同,无需使用此注解,@Identity用来标识对应主键的属性,同时可以用来指定是否需要将数据库生成的主键返回
reflaction:通过反射可以动态的生成sql语句,动态的给PreparedStatement的点位符赋值,也可以动态的生成VO对象,将记录类型转成Vo返回
泛型:通过泛型,程序员可以直接继承 BaseDao<T>来实现自己的DAO类
JDBC:访问数据库的基础
2.工程结构
类文件说明
Identity:标识属性为主键的注解
Table:标识VO类对应表名的注解
Book:VO类
BaseDao:Dao的父类,提供了插入和查询两个基本方法;
BookDao:Book类的DAO操作类
estBaseDao:测试类
3.代码
Identity.java
/** * 是否是主键 * @author Administrator * */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Identity {boolean value() default false;}
Table.java
/** * vo类对应的表名 * @author Administrator * */@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)@Target({ElementType.FIELD,ElementType.TYPE})public @interface Table {String value(); }
BaseDao.java
package com.oracle.dao;import java.lang.reflect.Field;import java.lang.reflect.ParameterizedType;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;import com.mysql.jdbc.Statement;import com.oracle.annotation.Identity;import com.oracle.annotation.Table;public class BaseDao<T> {private String url = "jdbc:mysql://localhost:3306/books";private String userName = "root";private String password = "tiger";/** * 获得数据库连接 * * @return */private Connection getConnection() {Connection conn = null;try {conn = DriverManager.getConnection(url, userName, password);} catch (Exception e) {e.printStackTrace();}return conn;}/** * 关闭资源 * * @param auto */private void close(AutoCloseable auto) {if (auto != null) {try {auto.close();} catch (Exception e) {e.printStackTrace();}}}/** * 获得表名 * * @param c * @return */private String getTableName(Class<?> c) {String table_name = c.getSimpleName();if (c.isAnnotationPresent(Table.class)) {table_name = c.getAnnotation(Table.class).value();}return table_name;}/** * 获得主键属性 * * @param c * @return */private Field getIdentifyField(Class<?> c) {// 获得所有的类属性信息;Field[] fs = c.getDeclaredFields();// 主键属性for (Field f : fs) {if (f.isAnnotationPresent(Identity.class)) {return f;}}return null;}/** * 获得普通的列属性 * * @param c * @return */private Field[] getColumnField(Class<?> c) {List<Field> list = new ArrayList<Field>();// 获得所有的类属性信息;Field[] fs = c.getDeclaredFields();// 主键属性for (Field f : fs) {if (!f.isAnnotationPresent(Identity.class)) {list.add(f);}}Field[] columnField = new Field[list.size()];return list.toArray(columnField);}/** * 生成插入的sql语句 * @param c * @return */private String makeInsertSql(Class<?> c) {// 1.获得表名String table_name = this.getTableName(c);// 2.定义插入的sql语句StringBuffer str = new StringBuffer("insert into " + table_name + "(");StringBuffer str_v = new StringBuffer(" values(");// 3.Field[] fs = this.getColumnField(c);// 4.遍历所有属性,生成sqlfor (int i = 0; i < fs.length; i++) {Field f = fs[i];str.append(f.getName());if (i == fs.length - 1) {str.append(")");str_v.append("?)");} else {str.append(",");str_v.append("?,");}}// 输入sqlstr.append(str_v);System.out.println(str);return str.toString();}/** * 持久化一个vo对象 * * @param t */protected void save(T t) {Class<?> c = t.getClass();//1.主键属性Field keyField = this.getIdentifyField(c);Field[] fs = this.getColumnField(c);//2.定义sqlString sql=this.makeInsertSql(c);//3.给ps赋值(1.赋值;主键不赋值 ;2.返回生成的主键)Connection conn = this.getConnection();PreparedStatement ps = null;ResultSet rs = null;try {// 是否需要返回主键if (keyField!=null) {ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);} else {ps = conn.prepareStatement(sql);}// 给所有非主键的字段赋值int i = 1;for (Field f : fs) {f.setAccessible(true);ps.setObject(i++, f.get(t));}// 4.执行sql语句ps.execute();// 5.是否返回主键,如果需要返回主键,则获得主键,并赋给vo的主键属性if (keyField!=null) {rs = ps.getGeneratedKeys();rs.next(); // 移动光标Object key = rs.getInt(1); // 主键keyField.setAccessible(true);keyField.set(t, key);}} catch (Exception e) {e.printStackTrace();} finally {// 8.关闭资源this.close(rs);this.close(ps);this.close(conn);}}/** * 根据条件查询记录,并组装成vo返回 * * @param where * @param args * @return */public List<T> query(String where, Object[] args) {List<T> list=new ArrayList<T>();ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();Class<?> c = (Class<?>) pt.getActualTypeArguments()[0];// 1.生成sqlString sql=this.makeSelect(c, where);//2.给ps赋值Connection conn = this.getConnection();PreparedStatement ps = null;ResultSet rs = null;Field[] fs=c.getDeclaredFields();try {ps=conn.prepareStatement(sql);if(args!=null) {for(int i=0;i<args.length;i++) {ps.setObject(i+1, args[i]);}}rs=ps.executeQuery();//遍历ResultSetwhile(rs.next()) {@SuppressWarnings("unchecked")T t=(T) c.newInstance();for(Field f:fs) {f.setAccessible(true);f.set(t, rs.getObject(f.getName()));}list.add(t);}} catch (Exception e) {e.printStackTrace();} finally {// 3.关闭资源this.close(rs);this.close(ps);this.close(conn);}System.out.println(c);return list;}/** * 带条件,无参数的查询 * @param where * @return */public List<T> query(String where){return this.query(where, null);}/** * 查询全部 * @param where * @return */public List<T> queryAll(){return this.query(null, null);}/** * 查询 * @param c * @param where * @return */private String makeSelect(Class<?> c,String where) {String sql="select * from "+this.getTableName(c)+" "+(where==null?"":where);return sql;}}
Book.java
package com.oracle.vo;import com.oracle.annotation.Identity;import com.oracle.annotation.Table;@Table("book")public class Book {@Identityprivate Integer isbn;private String bookName;private int price;public Integer getIsbn() {return isbn;}public void setIsbn(Integer isbn) {this.isbn = isbn;}public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}@Overridepublic String toString() {return "Book [isbn=" + isbn + ", bookName=" + bookName + ", price=" + price + "]";}public Book(Integer isbn, String bookName, int price) {super();this.isbn = isbn;this.bookName = bookName;this.price = price;}public Book() {super();}public Book(String bookName, int price) {super();this.bookName = bookName;this.price = price;}}
BookDao.java
package com.oracle.dao;import java.util.List;import com.oracle.vo.Book;public class BookDao extends BaseDao<Book> {@Overridepublic void save(Book t) {// TODO Auto-generated method stubsuper.save(t);}public List<Book> query() {return super.queryAll();}public List<Book> getWhere(String where,Object[] args) {return super.query(where,args);}public List<Book> getWhere(String where) {return super.query(where);}}
TestBaseDao
package com.oracle.test;import java.util.List;import com.oracle.dao.BookDao;import com.oracle.vo.Book;public class TestBaseDao {public static void main(String[] args) {//定义一个daoBookDao dao=new BookDao();Book b=new Book("世界之大,无其不有",56);//保存dao.save(b);System.out.println(b.getIsbn());//查询List<Book> list=dao.getWhere("where price=56 limit 4,5");for(Book k:list) {System.out.println(k);}}}
4.总结
以上例子虽然简单,但可以把持久层框架的主要功能的原理描述清楚,但还存在很多问题,数据库连接池,数据库参数的配置,事务控制,高级映射,缓存机制,数据的批量操作等功能都没有考虑;这些功能在以后的博客中还会持续增加;
5.源码下载
- 使用反射及Annotation自定义Dao组件
- android反射组件 (一)java 自定义annotation基础知识
- android反射组件 (一)java 自定义annotation基础知识
- Java自定义Annotation使用
- 使用反射来解析Annotation
- Annotation(自定义注解)反射获取注解
- 使用Java反射(Reflect)、自定义注解(Customer Annotation)生成简单SQL语句
- 使用自定义annotation完成注入
- 自定义注解Annotation的使用
- 使用自定义的Annotation&默认值
- java自定义annotation使用详解
- 泛型,反射,公共dao层的使用
- 使用反射来提取注解annotation
- 自定义组件及属性
- Annotation--反射与Annotation
- 如何自定义注解Annotation,并利用反射进行解析
- 简单自定义Annotation和利用反射获取注解中的值
- java 自定义注解annotation和通过反射获取注解
- tail 命令
- 官方安装文档解读SAP S4 HANA架构
- mysql变量 生效时间 where
- java源码阅读系列-ArrayList
- Field及其用法
- 使用反射及Annotation自定义Dao组件
- AI学习路线图【目录】
- ubuntu 安装截图工具 Shutter,并设置快捷键 Ctrl+Shift+X
- 数据库主键和外键
- R语言非度量MDS降维
- ElasticSearch返回空桶
- 打飞机游戏相关策划
- mybatis中对xml 中SQL处理大于号、小于号
- failed to resolve:com.android.support:appcompat-v7:27.+的报错