重溫Java持久化(一)持久化

  09年和朋友,寫了個仿SSH的框架例子,將其三塊代碼集成(仿structs、仿spring、仿hibernate),並作了個小網站(JSTL+JSP+(仿)SSH),採起這個框架,感受挺好用的。
主要目的是爲了提升對框架的認識,故沒有真正的SSH複雜,意在道明其因由,我的認爲,對於企業項目開發可以理解框架原理便可。
因仿hibernate的這塊代碼非本人所寫的,難免的有點點遺憾,前些日子無聊,又看到另個朋友採用註解寫了個小框架(針對android系統的),也想採用註解寫個試試。
通過幾天的折騰,也總算是出爐了。時間倉租,應該會有很多瑕疵,之後有時間,慢慢優化咯。
優勢:
1. 以對象方式操做數據庫,使用簡單方便.
2. 所依賴的jar包少,僅須要數據庫驅動的jar.
3. 以上兩個優勢,對於業務不復雜的小型系統來講,蠻方便的.
DMIS-JHibernate關鍵代碼 
DMIS-JHibernate.jar  DMIS-JHibernate_src.zip見附件
=====================================
先來看下註解的含義,見註釋
/* 
 * 元註解@Target,@Retention,@Documented,@Inherited 
 *  
 * @Target 表示該註解用於什麼地方,可能的 ElemenetType 參數包括: 
 *         ElemenetType.CONSTRUCTOR 構造器聲明 
 *         ElemenetType.FIELD 域聲明(包括 enum 實例) 
 *         ElemenetType.LOCAL_VARIABLE 局部變量聲明 
 *         ElemenetType.METHOD 方法聲明 
 *         ElemenetType.PACKAGE 包聲明 
 *         ElemenetType.PARAMETER 參數聲明 
 *         ElemenetType.TYPE 類,接口(包括註解類型)或enum聲明 
 *          
 * @Retention 表示在什麼級別保存該註解信息。可選的 RetentionPolicy 參數包括: 
 *         RetentionPolicy.SOURCE 註解將被編譯器丟棄 
 *         RetentionPolicy.CLASS 註解在class文件中可用,但會被VM丟棄 
 *         RetentionPolicy.RUNTIME VM將在運行期也保留註釋,所以能夠經過反射機制讀取註解的信息。 
 *          
 * @Documented 將此註解包含在 javadoc 中 
 *      
 * @Inherited 容許子類繼承父類中的註解 
 *    
 * @author ypf
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Table {
 /**
  * 表名
  * 
  * @return
  */
  public abstract String name();
}
=====================================
/**
 * 註解表 標識是否爲主鍵
 * @author ypf
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public abstract @interface Id {
}
=====================================
/**
 * 註解表 標識所映射的數據庫字段
 * 
 * @author ypf
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public abstract @interface Column {
 /**
  * 列名
  * @return String
  */
 public abstract String name();
 /**
  * 類型
  * @return String
  */
 public abstract String type() default "";
 /**
  * 類型
  * @return int
  */
 public abstract int length() default 0;
}
=====================================
/**
 * 數據庫輔助類
 * @author ypf
 */
public class DBHelper {
  Logger logger = Logger.getLogger(DBHelper.class.getName());
  private String driver;
  private String url;
  private String dbname;
  private String dbpass;
  public DBHelper(String driver, String url, String dbname, String dbpass) {
    super();
    this.driver = driver;
    this.url = url;
    this.dbname = dbname;
    this.dbpass = dbpass;
  }
  public Connection getConn() throws ClassNotFoundException, SQLException {
    Class.forName(driver);
    Connection conn = DriverManager.getConnection(url, dbname, dbpass);
    return conn;
 }
 /**
  * 釋放資源
  * 
  * @param conn-鏈接對象
  * @param pstmt-預編譯
  * @param rs-結果集
  */
  public void closeAll(Connection conn, PreparedStatement ps, ResultSet rs) {
    if (rs != null) {
      try {
        rs.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
    if (ps != null) {
      try {
        ps.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
    if (conn != null) {
      try {
        conn.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  }
 /**
  * 執行增、刪、改
  * @param sql-語句
  * @param params-數組型參數
  * @return int 受影響的行數
  * @throws SQLException
  * @throws ClassNotFoundException
  */
  public int executeUpdate(String sql, Object... params) throws SQLException, ClassNotFoundException {
    Connection connection = null;
    PreparedStatement ps = null;
    int num = 0;
    // 處理SQL,執行SQL
    try {
      connection = getConn(); // 獲得數據庫鏈接
      ps = connection.prepareStatement(sql); // 預處理SQL語句
      buildPreparedStatement(ps, params);
      logger.info("Oper: " + sql);
      num = ps.executeUpdate(); // 執行SQL語句
    }catch (SQLException e) {
      throw e;
    }catch (ClassNotFoundException e) {
      throw e;
    }finally {
      closeAll(connection, ps, null);
    }
    return num;
  }
 /**
  * 爲PreparedStatement對象填充參數
  * @param ps 預編譯句子
  * @param param 動態參數
  * @throws SQLException
  */
  public void buildPreparedStatement(PreparedStatement ps, Object... params) throws SQLException {
    // 設置參數
    for (int i = 0; i < params.length; i++) {
      // 將Date轉換成java.sql.Date
      if (params[i] instanceof Date) {
        Date d = (Date) params[i];
        ps.setObject(i + 1, new Timestamp(d.getTime()));
      } else {
        ps.setObject(i + 1, params[i]);
      }
    }
  }
 /**
  * 執行查詢操做
  * @param sql sql語句
  * @param param 動態參數
  * @return RowSet 結果集,可直接使用
  */
  public RowSet executeQuery(String sql, Object... params) throws SQLException, ClassNotFoundException {
    Connection connection = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    RowSet rowset = null;
    try {
      connection = this.getConn();
      ps = connection.prepareStatement(sql);
      buildPreparedStatement(ps, params);
      logger.info("Oper: " + sql);
      rs = ps.executeQuery();
      rowset = populate(rs);
    } catch (SQLException e) {
      throw e;
    } catch (ClassNotFoundException e) {
      throw e;
    } finally {
      closeAll(connection, ps, rs);
    }
    return rowset;
  }
 /**
  * 將ResultSet轉換爲RowSet對象
  * @param rs 數據集
  * @return RowSet
  */
  public RowSet populate(ResultSet rs) throws SQLException {
    CachedRowSetImpl crs = new CachedRowSetImpl();
    crs.populate(rs);
    return crs;
  }
 /**
  * 從RowSet中獲取列頭
  * @param rs 數據集
  * @return List
  */
  public List getRowSetColName(RowSet rs) throws SQLException {
    ArrayList collist = new ArrayList();
    for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
      collist.add(rs.getMetaData().getColumnName(i + 1).toUpperCase());
    }
    return collist;
  }
}
=====================================
/**
 * 用於建立表的輔助類
 * 
 * @author ypf
 */
public class TableHelper {
  private Logger log = Logger.getLogger(TableHelper.class.getName());
  private Session session;
  public TableHelper(Session session) {
    this.session = session;
  }
 /**
  * 建立表 
  * @param <T>
  * @param clazz
  */
  public <T> void createTable(Class<T> clazz) {
    String tableName = "";
    if (clazz.isAnnotationPresent(Table.class)) {
      Table table = (Table) clazz.getAnnotation(Table.class);
      tableName = table.name();
    } else {
      return;
    }
    StringBuilder sb = new StringBuilder();
    // 用來判斷表是否存在,若是存在則不執行改操做
    sb.append("CREATE TABLE ").append(tableName).append(" (");
    List<Field> allFields = ClassUtil.joinFields(clazz);
    for (Field field : allFields) {
      if (!field.isAnnotationPresent(Column.class)) {
        continue;
      }
      Column column = (Column) field.getAnnotation(Column.class);
      String columnType = "";
      // 判斷column的type字段是否爲空,若是爲空則根據字段的值將其轉換爲對應的數據庫類型
      if (column.type().equals(""))
        columnType = getColumnType(field.getType());
      else {
        columnType = getColumnType(column.type());
      }
      sb.append(column.name() + " " + columnType);
      if (column.length() != 0) {
        sb.append("(" + column.length() + ")");
      }
      // 添加主鍵
      if (field.isAnnotationPresent(Id.class)) {
        sb.append(" PRIMARY KEY");
      }
      sb.append(", ");
    }
    sb.delete(sb.length() - 2, sb.length() - 1);
    sb.append(")");
    String sql = sb.toString();
    String checkSql = "SELECT 1 FROM USER_TABLES WHERE TABLE_NAME=?";
    String dropSql = "DROP TABLE " + tableName.toUpperCase();
    try {
      RowSet rs = session.executeQuery(checkSql, tableName.toUpperCase());
      // 若是存在則先刪除
      if (rs.next()) {
        log.info("表[" + tableName.toUpperCase() + "]已經存在!");
        // session.executeUpdate(dropSql);
        // session.executeUpdate(sql);
      } else {
        session.executeUpdate(sql);
        log.info("表[" + tableName.toUpperCase() + "]建立成功!");
      }
    } catch (SQLException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
  }
  //根據字段類型返回數據庫對應的列,之後須要擴展優化,一遍支持多中數據庫,目前只支持oracle
  private String getColumnType(Class<?> fieldType) {
    if (String.class == fieldType) {
      return "VARCHAR";
    }
    if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
      return "NUMBER";
    }
    if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
      return "LONG";
    }
    if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
      return "NUMBER";
    }
    if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
      return "NUMBER";
    }
    if (Blob.class == fieldType) {
      return "BLOB";
    }
    if (Date.class == fieldType) {
     return "DATE";
    }
    return "VARCHAR";
  }
 /**
  * 根據傳入的類型返回對應的數據庫字段類型 若是找不到匹配的則直接用其自己做爲數據庫列類型(type不容許爲空)
  * 備註:這裏之後會擴展(根據不用的數據庫建立不用的字段)
  * @param type
  * @return String
  */
  private String getColumnType(String type) {
    if (ColumnType.INTEGER.equals(type)) {
      return "NUMBER";
    }
    if (ColumnType.STRING.equals(type)) {
      return "VARCHAR";
    }
    if (ColumnType.LONG.equals(type)) {
      return "LONG";
    }
    return type;
  }
}
=====================================
/**
 * 對外公開的數據庫訪問類
 * 
 * @author ypf
 */
public interface Session {
 /**
  * 類加載 
  */
  public abstract void loadContext(ClassLoad c);
 /**
  * 添加 
  */
  public abstract Serializable insert(Object entity) throws IllegalArgumentException, SecurityException, IllegalAccessException, NoSuchFieldException, Exception;
 /**
  * 刪除
  */
  public abstract Serializable delete(Object entity) throws SQLException, ClassNotFoundException;
 /**
  * 修改
  */
  public abstract Serializable update(Object entity) throws SQLException, ClassNotFoundException, IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException;
 /**
  * 根據id獲取對象
  */
  public abstract Object getResource(Serializable id, Class clazz) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException;
 /**
  * 查詢全部
  */
  public abstract List query(Class clazz) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException;
 /**
  * 封裝執行sql代碼.
  */
  public int executeUpdate(String sql, Object... params) throws SQLException, ClassNotFoundException;
 /**
  * 經過sql語句,進行查詢操做
  * @param sql sql預警
  * @param params 參數
  * @return RowSet
  */
  public RowSet executeQuery(String sql, Object... params) throws SQLException, ClassNotFoundException;
 /**
  * 經過sql語句,進行增、刪、改操做
  * @param sql sql預警
  * @param params 參數
  * @return RowSet
  */
  public Object executeQueryUnique(String sql, Object... params) throws SQLException, ClassNotFoundException;
 //未完待續...
}
=====================================
/**
 * 提供CRUD操做的實現類
 * @author ypf
 */
public class SessionImpl implements Session {
  private Logger log = Logger.getLogger(SessionImpl.class.getName());
  DBHelper dbHelper; // 數據庫訪問類
  Class clazz; // 當前處理對象
  String tableName; // 代表
  List<Field> allFields; // 全部字段
  String keyName; // 主鍵
  public void loadContext(ClassLoad c) {
    c.execute();
  }
 /**
  * 構建列信息,如:name,type
  * @return String
  */
  private String buildStrColumn() {
    String step = "";
    for (int i = 0; i < allFields.size(); i++) {
      Column column = (Column) allFields.get(i).getAnnotation(Column.class);
      step += column.name() + ",";
    }
    if (step.length() > 0)
      step = step.substring(0, step.length() - 1);
    }else {
      step = "*";
    }
    return step;
  }
 /**
  * 構建參數信息,如:?,?
  * @return String
  */
  private String buildValColumn() {
    String step = "";
    for (int i = 0; i < allFields.size(); i++) {
      step += "?,";
    }
    if (step.length() > 0)
      step = step.substring(0, step.length() - 1);
    return step;
 }
 /**
  * 初始化
  * 
  * @param clazz
  */
  private void initProperites(Class clazz) {
    this.clazz = clazz;
    if (this.clazz.isAnnotationPresent(Table.class)) {
      Table table = (Table) clazz.getAnnotation(Table.class);
      this.tableName = table.name();
    }
    this.allFields = ClassUtil.joinFields(clazz);
    for (Field field : allFields) {
      if (!field.isAnnotationPresent(Column.class)) {
        continue;
      }
      Column column = (Column) field.getAnnotation(Column.class);
      if (field.isAnnotationPresent(Id.class)) {
        this.keyName = field.getName();
      }
    }
    log.info("clazz:" + this.clazz + " tableName:" + this.tableName + " keyName:" + this.keyName);
  }
  public SessionImpl(DBHelper dbHelper) {
    this.dbHelper = dbHelper;
  }
  @Override
  public Serializable delete(Object entity) throws SQLException, ClassNotFoundException {
    initProperites(entity.getClass());
    Object keyValue = ClassUtil.getPropertie(entity, keyName);
    String sql = "delete from {0} where {1}=?".replace("{0}", this.tableName).replace("{1}", keyName);
    log.info("[delete]:" + sql);
    log.info("[params]:" + keyValue);
    return dbHelper.executeUpdate(sql, keyValue);
  }
  @Override
  public Object getResource(Serializable id, Class clazz) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
    initProperites(clazz);
    String cols = buildStrColumn();
    String sql = ClassUtil.formartString("SELECT {0} FROM {1} where {2}=?", new String[] { cols, this.tableName, this.keyName });
    log.info("[get]:" + sql);
    log.info("[params]:" + id);
    RowSet rs = dbHelper.executeQuery(sql, id);
    List list = ClassUtil.buildEntities(rs, clazz, allFields);
    if (list.size() > 0)
      return list.get(0);
    return null;
  }
  // 插入
  @Override
  public Serializable insert(Object entity) throws Exception {
    initProperites(entity.getClass());
    String cols = buildStrColumn();// 要查詢的字段
    String vs = buildValColumn();// 預編譯參數
    String sql = ClassUtil.formartString("insert into {0}({1}) values({2})", new String[] { this.tableName, cols, vs });
    Object[] params = ClassUtil.buildParams(entity, allFields);
    return dbHelper.executeUpdate(sql, params);
  }
  @Override
  public Serializable update(Object entity) throws SQLException, ClassNotFoundException, IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    initProperites(entity.getClass());
    String cols = buildStrColumn();
    String vs = buildValColumn();
    String _cols = (cols + ",").replace(",", "=?,");
    _cols = _cols.length() > 0 ? _cols.substring(0, _cols.length() - 1) : "*";
    Object[] params = ClassUtil.buildParams(entity, allFields);
    Object vKey = ClassUtil.buildParams(entity, keyName);
    Object[] _params = new Object[params.length + 1];
    for (int i = 0; i < params.length; i++) {
     _params[i] = params[i];
    }
    _params[params.length] = vKey.toString();
    String sql = ClassUtil.formartString("update {0} set {1} where {2}=? ", new String[] { this.tableName, _cols, this.keyName });
    return dbHelper.executeUpdate(sql, _params);
  }
  @Override
  public List query(Class clazz) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
    initProperites(clazz);
    String cols = buildStrColumn();
    String sql = ClassUtil.formartString("SELECT {0} FROM {1}", new String[] { cols, this.tableName });
    RowSet rs = dbHelper.executeQuery(sql);
    List list = ClassUtil.buildEntities(rs, clazz, allFields);
    return list;
  }
  @Override
  public int executeUpdate(String sql, Object... params) throws SQLException, ClassNotFoundException {
    return dbHelper.executeUpdate(sql, params);
  }
  @Override
  public RowSet executeQuery(String sql, Object... params) throws SQLException, ClassNotFoundException {
    return dbHelper.executeQuery(sql, params);
  }
  @Override
  public Object executeQueryUnique(String sql, Object... params) throws SQLException, ClassNotFoundException {
    RowSet rs = dbHelper.executeQuery(sql, params);
      if (rs.next())
        return rs.getObject(1);
    return null;
  }
}
=====================================
/**
 * 輔助類
 * @author ypf
 */
public class ClassUtil {
 /**
  * 合併Field數組並去重,並實現過濾掉非Column字段,和實現Id放在首字段位置功能
  * @param clazz
  * @return 因此字段
  */
  public static List<Field> joinFields(Class clazz) {
    List<Class> cList = new ArrayList();
    List<Field> fList = new ArrayList();
    // 獲取全部類
    findAllClass(clazz, cList);
    // 獲取全部字段
    for (Class c : cList) {
      for (int i = 0; i < c.getDeclaredFields().length; i++) {
        fList.add(c.getDeclaredFields()[i]);
      }
    }
    Map<String, Field> map = new LinkedHashMap<String, Field>();
    for (Field field : fList) {
     // 過濾掉非Column定義的字段
     if (!field.isAnnotationPresent(Column.class)) {
      continue;
     }
     Column column = (Column) field.getAnnotation(Column.class);
     map.put(column.name(), field);
    }
    List<Field> list = new ArrayList<Field>();
    for (String key : map.keySet()) {
      Field step = map.get(key);
      // 若是是Id則放在首位置.
      if (step.isAnnotationPresent(Id.class)) {
        list.add(0, step);
      } else {
        list.add(step);
      }
    }
    return list;
   }
 /**
  * 查找全部類:自身及全部的父類(接口除外)
  * 
  * @param clazz
  * @param list
  */
  private static void findAllClass(Class<?> clazz, List list) {
    // 添加自身Class
    if (list.size() == 0)
    list.add(clazz);
    Class<?> c = clazz.getSuperclass();
    if (c != null) {
     list.add(c);
     findAllClass(c, list);
    }
  }
 /**
  * 建立類及封裝屬性
  * @param clazz
  * @param fileds
  * @param values
  * @return size
  */
  public static Object buildProperties(Class clazz, List<Field> fileds, List values) throws InstantiationException, IllegalAccessException {
    if (values.size() != fileds.size())
      throw new RuntimeException("fileds的size和values的size不一致!");
    Object obj = clazz.newInstance();
    for (int i = 0; i < fileds.size(); i++) {
      buildPropertie(obj, fileds.get(i), values.get(i));
    }
    return obj;
  }
 /**
  * 給對象的某個字段封裝數值
  */
  public static void buildPropertie(Object obj, Field f, Object value) {
    try {
       String methodName = buildSetMethod(f.getName());
       // 給某個字段封裝數值,methodName方法名,obj.getClass().getMethod(buildGetMethod(f.getName())).getReturnType()返回類型
       // invoke執行方法,obj要賦值的對象,value要賦的值
       obj.getClass().getMethod(methodName, obj.getClass().getMethod(buildGetMethod(f.getName())).getReturnType()).invoke(obj, value);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 /**
  * 構建get方法
  * @param fieldName
  * @return String
  */
  public static String buildGetMethod(String fieldName) {
    String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    return methodName;
  }
 /**
  * 構建set方法
  * @param fieldName
  * @return String
  */
  public static String buildSetMethod(String fieldName) {
    String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    return methodName;
  }
 /**
  * 根據字段名或對象對應的get方法值
  * @param obj 對象
  * @param fieldName字段名
  * @return Object
  */
  public static Object getPropertie(Object obj, String fieldName) {
    Object val = "";
    try {
      String methodName = buildGetMethod(fieldName);
      val = obj.getClass().getMethod(methodName).invoke(obj);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return val;
 }
 /**
  * 根據字段獲取對應的值
  * @param entity
  * @param allFields
  * @return Object[]
  */
  public static Object[] buildParams(Object entity, List<Field> fields) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    Object[] params = new Object[fields.size()];// 字段參數值
    for (int i = 0; i < fields.size(); i++) {
      Field f = fields.get(i);
     String methodName = ClassUtil.buildGetMethod(f.getName());
      Object v = entity.getClass().getMethod(methodName).invoke(entity);
      if (v instanceof Enum) {
        v = ((Enum) v).ordinal();
      }
      params[i] = v;
      }
    return params;
  }
  public static Object buildParams(Object entity, Field field) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    String methodName = ClassUtil.buildGetMethod(field.getName());
    Object v = entity.getClass().getMethod(methodName).invoke(entity);
    return v;
  }
  public static Object buildParams(Object entity, String fieldName) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    String methodName = ClassUtil.buildGetMethod(fieldName);
    Object v = entity.getClass().getMethod(methodName).invoke(entity);
    return v;
  }
 /**
  * 格式化
  * @param str
  * @param params
  * @return String
  */
  public static String formartString(String str, Object... params) {
    for (int i = 0; i < params.length; i++) {
    Object obj = params[i];
    if (obj != null)
      str = str.replace("{" + i + "}", obj.toString());
    }
   return str;
  }
  public static List buildEntities(RowSet rs, Class clazz, List<Field> allFields) throws SQLException, InstantiationException, IllegalAccessException {
    List<String> listCols = getRowSetColName(rs);
    List list = new ArrayList();
    while (rs.next()) {
      List values = new ArrayList();
      for (String key : listCols) {
        values.add(rs.getObject(key));
      }
      Object obj = ClassUtil.buildProperties(clazz, allFields, values);
      list.add(obj);
    }
    return list;
  }
  public static List getRowSetColName(RowSet rs) throws SQLException {
    List collist = new ArrayList();
    for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
      collist.add(rs.getMetaData().getColumnName(i + 1).toUpperCase());
    }
    return collist;
  }
}
相關文章
相關標籤/搜索