深入理解Java的Annotation系列-第五部分 使用註解編寫ORM框架
一、什麼是ORM?
物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/Rmapping),是一種程式技術,隨著面向物件的發展而產生的。用來把物件模型表示的物件對映到基於S Q L 的關係模型資料庫結構中去,或者把表中的一條記錄自動封裝成物件。
採用ORM優勢在於,程式設計師採用面向物件的方法來訪問資料庫,簡化了編碼,提高了開發速度,ORM自動完成類和表,屬性名和欄位名的對映。
使用本ORM框架,在處理查詢業務邏輯時,只要編寫形如"from 類名"的SQL語句,就可以得到封裝好的所查詢所有結果的List集合,處理新增業務時,只要呼叫Add(obj)方法即可實現新增功能。其他的功能讀者可自行新增。
二、整體思路
1、自定義ORM註解,包含@Table和@Column。
2、寫一個類,解析註解資訊,並存入Map物件
3、實現查詢和新增功能
4、使用自定義的ORM框架,實現業務邏輯
5、測試
三、具體實現
1、整體架構
2、建表並插入資料的SQL
showdatabases;
create database czf;
use czf;
create table stu(id int primary key,namevarchar(40),age int);
insert into stuvalues(1,'czf',34),(2,'afeng',25);
select * from stu;
createtable teacher(tid int primary key,tname varchar(40),tage int);
insertinto teacher values(1,'czf',34),(2,'afeng',25);
insert into teacher(tid,tname,tage)values(3,'czf3',33);
select * from teacher;
3、具體程式碼
第一部分 ORM部分程式碼的編寫
3.1 Table.java
packagecn.com.bochy.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定義註解,用於註解類名所對應的表名
* @authorchenzhengfeng
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String value();//表名
}
3.2 Column.java
package cn.com.bochy.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定義註解,用於註解物件的屬性名所對應的表的列名
* @authorchenzhengfeng
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String value();//列名
}
3.3 OrmImpl.java
package cn.com.bochy.orm;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import cn.com.bochy.annotation.Column;
import cn.com.bochy.annotation.Table;
/**
* 解析註解資訊,並存入Map中
* @authorchenzhengfeng
*/
public class OrmImpl {
//用於儲存類名對應的表名,其中key是類名,value是表名
private Map<String,String>mapTable=newHashMap<String,String>();
//用於屬性名對應的表的欄位名,其中key是屬性名,value是欄位名
private Map<String,String>mapColumns=newHashMap<String,String>();
public Map<String, String> getMapTable() {
returnmapTable;
}
public void setMapTable(Map<String, String> mapTable) {
this.mapTable =mapTable;
}
private StringtableName="";
public String getTableName() {
returntableName;
}
public void setTableName(String tableName) {
this.tableName =tableName;
}
public Map<String, String> getMapColumns() {
returnmapColumns;
}
public void setMapColumns(Map<String, String> mapColumns) {
this.mapColumns =mapColumns;
}
/**
* 解析實體類的註解資訊,其中c1是實體類的類物件
* @param c1
*/
public void parseAnnotation(Class<?> c1) {
Table table=c1.getAnnotation(Table.class);
tableName=table.value();//獲取註解的表名
mapTable.put(c1.getName(),tableName);//存入
Field[] fields=c1.getDeclaredFields();//獲取所有的屬性名
for(Fieldf:fields) {//遍歷屬性名
if(!f.getName().equals("serialVersionUID")) {
Column c=f.getAnnotation(Column.class);
mapColumns.put(f.getName(),c.value());//獲取該屬性名所對應的欄位,並存入
}
}
}
}
3.4 OrmQuery.java
package cn.com.bochy.orm;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import cn.com.bochy.dbutil.DBHepler;
/**
* 實現查詢功能
* @authorchenzhengfeng
*
*/
public class OrmQuery {
DBHepler helper=new DBHepler();
private static OrmImpl orm=null;
private static String tableName="";
private static Map<String,String> mapColumns=null;//儲存屬性和欄位對應關係的MAP
private static Map<String,String> mapTables=null;//儲存類名和表名對應關係的MAP
private Class<?>classc1;//查詢物件的類物件
/**
* 通過構造方法實現初始化工作
* @param c1
*/
public OrmQuery(Class<?>c1) {
this.classc1=c1;
orm=new OrmImpl();
orm.parseAnnotation(classc1);//解析要查詢物件的註解資訊
tableName=orm.getTableName();
mapColumns=orm.getMapColumns();
mapTables=orm.getMapTable();
}
/**
* 查詢sql形如"from類名"格式的語句,並封裝成List,其他的形式請讀者自行新增
* @param hql
* @return
*/
@SuppressWarnings("rawtypes")
public List query(Stringhql){
int index=hql.indexOf("from");
/**
* 以下語句是從hql語句中擷取類名
*/
StringclassName="";//類名
StringfullclassName="";//包含包名的類名
Stringsql="";
Stringhqlsub=hql.substring(index+5);//form的長度為4,再加上空格,所以為5
className=hqlsub;
//遍歷mapTables,查詢類名對應的表名
for(Stringkey:mapTables.keySet()) {
if(key.contains(className)) {
tableName=mapTables.get(key);
fullclassName=key;
}
}
sql="select * from "+tableName;
ResultSet rs= helper.query(sql, null);
List<Object>lists=new ArrayList<Object>();
try {
while(rs.next()) {
Class<?>c1= Class.forName(fullclassName); //查詢物件的類物件
Objects= c1.newInstance();//建立一個查詢物件
Field[]fs= c1.getDeclaredFields();//獲取該物件的所有屬性
for(Fieldf:fs) {//遍歷屬性
String fname= f.getName();//獲取某個屬性名
StringsetMethod="set"+FirstBig(fname);//某個屬性名對應的setter方法名
Method[] methods=c1.getDeclaredMethods();//獲取該物件的所有方法
for(Methodm:methods) {//遍歷方法
if(m.getName().equals(setMethod)) {//如果找到對應的方法
String columnName=mapColumns.get(fname);//屬性名對應的欄位名
m.invoke(s,rs.getObject(columnName));//執行該setter方法,給物件m賦值
break;
}
}
}
lists.add(s);//把物件存入列表
}
} catch (SQLException |ClassNotFoundException | InstantiationException | IllegalAccessExceptione) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(IllegalArgumentExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (InvocationTargetExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
return lists;
}
//把第一個字元變為大寫
public String FirstBig(Stringstr) {
returnstr.substring(0,1).toUpperCase()+str.substring(1);
}
}
3.5 OrmAdd.java
package cn.com.bochy.orm;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import cn.com.bochy.dbutil.DBHepler;
/**
* 實現ORM中的新增功能
* @authorchenzhengfeng
*/
public class OrmAdd {
DBHepler helper=new DBHepler();
private static OrmImpl orm=null;
private static Map<String,String> mapColumns=null;
private Class<?>classc1;//指定要新增的物件的類型別
//通過構造方法初始化
public OrmAdd(Class<?>c1) {
this.classc1=c1;
orm=new OrmImpl();
orm.parseAnnotation(classc1);//解析註解資訊
mapColumns=orm.getMapColumns();//獲取屬性名和欄位名的對應資訊
}
/**
* 通過Java的反射機制結合註解資訊實現新增功能
* @param obj
* @return
*/
public boolean add(Object obj) {
//獲取表名
for(String key:mapTables.keySet()) {
if(key.equals(obj.getClass().getName())) {
tableName=mapTables.get(key);
}
}
Method[] methods= obj.getClass().getDeclaredMethods();//獲取新增物件中所有的方法
Field[] fileds=obj.getClass().getDeclaredFields();//獲取新增物件中所有的屬性
String sqlColumn="";//用於拼接要新增表中所有的欄位
String sqlvalue="";//用於拼接要新增的所有值,用?代替
List<Object> parmas=newArrayList<Object>();//儲存要新增的所有值
for(Fieldf:fileds)//遍歷屬性
for(Methodm:methods) {//遍歷方法
//獲取該屬性對應的getter方法
if(m.getName().equals("get"+FirstBig(f.getName()))) {
Object values1;
try {
values1 = m.invoke(obj);//呼叫該物件的getter方法
parmas.add(values1);//把新增的值存入列表
sqlColumn+=mapColumns.get(f.getName())+",";
sqlvalue+="?,";
} catch (IllegalAccessExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (IllegalArgumentExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (InvocationTargetExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
sqlColumn=CutoutLastChar(sqlColumn);//把最後一個","去掉
sqlvalue=CutoutLastChar(sqlvalue);//把最後一個","去掉
String sql="insert into "+tableName+"("+sqlColumn+")"+" values("+sqlvalue+")";
Object[] param=parmas.toArray();//把集合列表轉化為陣列
return helper.noQuery(sql, param); //呼叫helper物件中noQuery實現新增功能
}
/**
* 去掉字串最後一個字元
* @param str
* @return
*/
public String CutoutLastChar(Stringstr) {
returnstr.substring(0,str.length()-1);
}
/**
* 把字串的首字元變為大寫
* @param str
* @return
*/
public String FirstBig(Stringstr) {
returnstr.substring(0,1).toUpperCase()+str.substring(1);
}
}
3.6 DBHepler.java
package cn.com.bochy.dbutil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 簡單的JDBC的封裝
* @authorchenzhengfeng
*
*/
public class DBHepler {
private Stringurl="jdbc:mysql://localhost:3306/czf";
private Stringuser="root";
private Stringpassword="root";
public Connectionconn=null;
public PreparedStatementpstmt=null;
public ResultSetrs=null;
//1、得到連線物件
public ConnectiongetConnection(){
try {
Class.forName("com.mysql.jdbc.Driver");
conn=DriverManager.getConnection(url,user, password);
} catch (ClassNotFoundExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (SQLExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
return conn;
}
//2、關閉資源
public void closeAll(){
try {
if(rs!=null){
rs.close();
}
if(pstmt!=null){
pstmt.close();
}
if(conn!=null){
conn.close();
}
} catch (SQLExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
//3、通用查詢方法
public ResultSetquery(Stringsql,Object[] param){
try {
getConnection();
pstmt=conn.prepareStatement(sql);
if(param!=null)
for(inti=0;i<param.length;i++){
pstmt.setObject(i+1,param[i]);
}
rs=pstmt.executeQuery();
} catch (SQLExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
returnrs;
}
//4、通用非查詢方法
public boolean noQuery(String sql,Object[]param){
getConnection();
int a=0;
try {
pstmt=conn.prepareStatement(sql);
if(param!=null)
for(inti=0;i<param.length;i++){
pstmt.setObject(i+1,param[i]);
}
a=pstmt.executeUpdate();
} catch (SQLExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
closeAll();
if(a>0)
return true;
else
return false;
}
}
第二部分 ORM應用
3.7 實體類Stu.java
package cn.com.bochy.entity;
import java.io.Serializable;
import cn.com.bochy.annotation.Column;
import cn.com.bochy.annotation.Table;
/**
* 實體類
* @author Administrator
*
*/
@Table("stu")//通過註解,類Stu對應表stu
public class Stu implements Serializable {
private static final long serialVersionUID = 1L;
@Column("id")//通過註解,屬性名id對應欄位名(列名)id
private int id;
public int getId() {
returnid;
}
public void setId(intid) {
this.id =id;
}
public String getName() {
returnname;
}
public void setName(String name) {
this.name =name;
}
public int getAge() {
returnage;
}
public void setAge(intage) {
this.age =age;
}
@Column("name")//通過註解,屬性名name對應欄位名(列名)name
private String name;
@Column("age")//通過註解,屬性名age對應欄位名(列名)age
private int age;
public Stu() {
// TODO Auto-generatedconstructor stub
}
}
3.8 實體類Teacher.java
package cn.com.bochy.entity;
import java.io.Serializable;
import cn.com.bochy.annotation.Column;
import cn.com.bochy.annotation.Table;
@Table("teacher")//通過註解,類Teacher對應表teacher
public class Teacher implements Serializable {
private static final long serialVersionUID = 1L;
@Column(value="tid")//通過註解,屬性名id對應欄位名(列名)tid
private int id;
public int getId() {
returnid;
}
public void setId(intid) {
this.id =id;
}
public String getName() {
returnname;
}
public void setName(String name) {
this.name =name;
}
public int getAge() {
returnage;
}
public void setAge(intage) {
this.age =age;
}
@Column("tname")//通過註解,屬性名name對應欄位名(
前面的話
一般地,使用readystatechange事件探測HTTP請求的完成。XHR2規範草案定義了進度事件Progress Events規範,XMLHttpRequest物件在請求的不同階段觸發不同型別的事件,所以它不再需要檢査readyState屬性。這個草案
一、什麼是ORM?
物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/Rmapping),是一種程式技術,隨著面向物件的發展而產生的。用來把物件模型表示的物件對映到基於S
Q L 的關係模型資料庫結構中去,或者把表中的
一、整體思路
1、先自定義一個用於許可權管理的註解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public
@interface Authority {
String modu ssa stream servlet實例 可用 igel sse ould rip alt
前言
Context容器是一個Web項目的代表,主要管理Servlet實例,在Tomcat中Servlet實例是以Wrapper出現的。如今問題是怎樣才幹通過C blob selected 單選框 encode 展示 條目 種類型 %20 寫代碼 前面的話
現代Web應用中頻繁使用的一項功能就是表單數據的序列化,XMLHttpRequest 2級為此定義了FormData類型。FormData為序列化表單以及創建與表單格式相同的 row 用戶數據 方便 案例 默認方法 span target osi content 前面的話
在以前,網站的用戶與後端交互的主要方式是通過HTML表單的使用。表單的引入在1993年,由於其簡單性和易用性,直到電子商務出現之前一直保持著重要位置。理解表單提交,對於更深 gin 開發工程師 tar component fin hasattr mar tex 員工 前面的話
雖然ajax全稱是asynchronous javascript and XML。但目前使用ajax技術時,傳遞JSON已經成為事實上的標準。因為相較於XML而言,J
轉載地址https://www.jianshu.com/p/4586dc676807
編寫執行的快的程式有三個因素:①選擇合適的演算法和資料結構;②理解編譯器的能力,使用有效的方式讓編譯器能進行優化;③對於運算量特別大的程式,可能還需要進行任務分解。在這一過程中可能還需要對程式的可讀性和執
我們先了解一下域名地址的組成:http:// www . google : 8080 / script/jquery.js
http:// (協議號)
www (子域名)
google (主域名)
8080 (埠號)
scrip
前面的話
我們接收到的響應主體型別可以是多種形式的,包括字串String、ArrayBuffer物件、二進位制Blob物件、JSON物件、javascirpt檔案及表示XML文件的Document物件等。下面將針對不同的主體型別,進行相應的響應解碼
屬性
在介紹響
下面的計算計算多項式的兩種不同方法,形如 a0+a1x+a2x^2········
第二個函式是根據horner法,通過反覆提出冪,來減少乘法的次數,按照道理說,既然polyh函式比poly函式減少了乘法的次數,那應該比poly快才對,可是事實正好相反,poly 彈出 例子 深入理解java logs title 最終 pre 有變 context 前面的話
對於執行環境(execution context)和作用域(scope)並不容易區分,甚至很多人認為它們就是一回事,只是高程和犀牛書關於作用域的兩種不同翻譯而已。但實際上, 前面的話
根據閉包的定義,我們知道,無論通過何種手段,只要將內部函式傳遞到所在的詞法作用域以外,它都會持有對原始作用域的引用,無論在何處執行這個函式都會使用閉包。接下來,本文將詳細介紹閉包的10種形式
返回值
最常用的一種形式是函式作為返回值被返回
var F = function() 前面的話
對於執行環境(execution context)和作用域(scope)並不容易區分,甚至很多人認為它們就是一回事,只是高程和犀牛書關於作用域的兩種不同翻譯而已。但實際上,它們並不相同,卻相互糾纏在一起。本文先用一張圖開宗明義,然後進行術語的簡單解釋,最後根據圖示內容進行詳細說明
圖示
儘管客戶端不能直接通過Secondary進行寫操作,客戶端能通過secondary進行資料讀取操作,一個secondary也可以在primary不可達的情況下轉換成primary,同時也可以自主制定一些配置來賦予secondary特殊功能:
$0 一個 編譯 存儲器 系統 32位 做了 ++i 擴展 這2章總結的很少,主要是覺得沒那麽重要。
1.2個操作數的指令,第二個操作數通常是目的操作數:movb a b,move a to b,而add a b,b+=a,指令分為指令類,如mov類:movb,movw,m
深入,並且廣泛
-沉默犀牛
文章導讀
計算機執行機器程式碼,用位元組序列編碼低階的操作,包括處理資料、管理記憶體、讀寫儲存裝置上的資料,以及利用網路通訊。編譯器基於程式語言的規則、目標機器的指令集和作業系統遵循的慣例,經過一系列的階段生成機器程式碼。GCC C語言編譯器以彙
5.13
A.
畫圖:
關鍵路徑為第三幅圖加粗部分
B.
下界為浮點加法的延遲界限,CPE 為 3.00
C.
整數加法的延遲界限,CPE 為 1.00
D.
關鍵路徑上只有浮點加法
5.14
v fas get toolbar 影響 運算 描述 ssa reference 保持 對象克隆
對象復制,又叫對象克隆,可以通過 clone 關鍵字來完成
在多數情況下,我們並不需要完全復制一個對象來獲得其中屬性。但有一個情況下確實需要:如果你有一個窗口對象,該對象持 復用 類型 橋接 職責鏈模式 學習 組合 設計模式之代理模式 職責 理論 該文用於自我學習~
來自:湯姆大叔 深入理解JavaScript系列文章,包括了原創,翻譯,轉載,整理等各類型文章,如果對你有用,請推薦支持一把,給大叔寫作的動力。
深入理解JavaScript系 相關推薦
深入理解ajax系列第五篇
深入理解Java的Annotation系列-第五部分 使用註解編寫ORM框架
深入理解Java的Annotation系列-第四部分 註解的應用-使用註解實現許可權管理
深入理解Tomcat系列之五:Context容器和Wrapper容器
深入理解ajax系列第四篇
深入理解ajax系列第八篇
深入理解ajax系列第七篇
深入理解計算機系統----第五章優化程式效能
深入理解AJAX系列第四篇--跨域問題
深入理解ajax系列第三篇——響應解碼
一個絕對注意不到的小細節(深入理解計算機系統第五章5.5及5.6)
深入理解javascript作用域系列第五篇
深入理解閉包系列第五篇——閉包的10種形式
深入理解javascript作用域系列第五篇——一張圖理解執行環境和作用域
第五部分 架構篇 第十三章 MongoDB Replica Sets 架構(成員深入理解)
深入理解計算機系統 第三章大略和第五章大略
深入理解計算機系統_第一部分_第三章_程式的機器級表示
[第五章] 深入理解計算機系統第三版 家庭作業參考答案
前端學PHP之面向對象系列第五篇——對象操作
深入理解JavaScript系列