java封裝呼叫儲存過程
之前閒來無事在研究儲存過程 覺得jdbc呼叫儲存過程效率太低就想有沒有更高效的方式?最好能用面對物件思想一個方法呼叫, 傳入過程名稱就好?於是打開了百度搜索一番 還真找到了一篇很讚的文章,英雄所見略同啊,想到一塊去了 博主已經封裝的很好了 叫 然後沒有了 what? 有一那肯定還有二啊,說明一是不全的 那麼我理所當然的去搜索二 納尼? 沒有 次奧 說明這個博主很懶!最起碼比我懶,好了開玩笑的,不過這個博主已經寫的很好很好了 但還是無法真正投入使用 乾脆我就用博主的思路繼續重新寫一篇完整的好了,這次的目的是繼續封裝生成一個jar包 以後匯入就可以用了 這個包後面我會上傳的 建議先看上面那個部落格後再來看 因為思想一樣很多話就沒必要在重複講解了
需要用到這兩個包
首先需要兩個有關係的java實體bean
這裡就用orcle中的emp和dept表也就是員工和部門表
首先是emp實體物件
package test.bean;
import java.util.Date;
public class Emp {
private int empno;
private String ename;
private String job;
private int mgr;
private Date hiredate;
private double sal;
private double comm;
// int deptno;
private Dept dept;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public int getEmpno() {
return empno;
}
public void setEmpno(int empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public int getMgr() {
return mgr;
}
public void setMgr(int mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public double getComm() {
return comm;
}
public void setComm(double comm) {
this.comm = comm;
}
// public int getDeptno() {
// return deptno;
// }
// public void setDeptno(int deptno) {
// this.deptno = deptno;
// }
@Override
public String toString() {
return "Emp [empno=" + empno + ", ename=" + ename + ", job=" + job + ", mgr=" + mgr + ", hiredate=" + hiredate
+ ", sal=" + sal + ", comm=" + comm + ", dept=" + dept + "]";
}
}
我註釋的部分就是那位那位很懶的博主所描述的不全的部分,因為很多什麼我們要查的物件是有關聯關係的
然後是dept實體物件
package test.bean;
public class Dept {
private int deptno;
private String dname;
private String loc;
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
@Override
public String toString() {
return "Dept [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
}
}
這個就沒什麼好講的了
第二步我們的dao層
介面我就不寫了
package test.dao.imp;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import qin.common.ProcessingCenter;
import test.DBHelper;
import test.bean.Dept;
import test.bean.Emp;
import test.dao.EmpDao;
import test.dao.ProxyObjects;
public class EmpDaoImpl extends ProxyObjects implements EmpDao {
/*
*數字代表傳入引數
*返回的是一個MAP集合 key(int)對應傳出引數的個數(按序)
*1代表普通型別 2代表物件型別 3代表集合型別
*
*字母代表傳出引數
*c代表遊標
*s代表String
*i代表Integer
*o代表double
*d代表data
*/
// 測試 sql 更具id獲取物件
@Override
public Emp finEmp(int id) throws Exception {
String SQL="select * from emp where empno=? ";
List<Emp> list = (List<Emp>) pr.executefindsql(SQL,Emp.class);
return list.get(0);
}
// 測試 sql 更新操作
@Override
public int updateEmp(String ename, int id) throws Exception {
// TODO Auto-generated method stub
String SQL = "update emp set ename = ? where empno = ?";
return pr.executeUpdatesql(SQL);
}
// 測試儲存過程 根據編號獲取物件
@Override
public Emp getEmpbyid(int id) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call getEmpbyid({1},{c})}";
Map<Integer, Object> map = pr.execute(SQL, Emp.class);
List<Emp> list = (List<Emp>) map.get(0);
return list.get(0);
}
// 測試儲存過程 根據編號 獲取集合
@Override
public List<Map<String, Object>> getListbyid(int id) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call getEmpbyid({1},{c})}";
return (List<Map<String, Object>>) pr.execute(SQL).get(0);
}
// 測試儲存過程 根據使用者名稱稱獲取物件集合
@Override
public List<Emp> getEmpListByEname(String ename) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call getEmpListByEname({1},{c})}";
Map<Integer, Object> execute = pr.execute(SQL,Emp.class);
return (List<Emp>) execute.get(0);
}
// 測試儲存過程 新增物件
@Override
public void addEmp(Emp emp) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call addEmp({2})}";
//如果想傳入一個物件進行新增必須在資料庫建立對應資料型別
//第一個為物件型別,第二個為集合型別 第三個為關聯欄位 如果關聯欄位不同 以被關聯物件的關聯欄位為準 這裡的deptno為dept物件中的管理欄位
String[] li={"EMPOBJ","EMPLIST","deptno"};
pr.execute(li, SQL);
}
// 測試儲存過程 新增集合
@Override
public void addEmps(List<Emp> list) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call addEmp({3})}";
//如果想傳入一個物件進行新增必須在資料庫建立對應資料型別
//第一個為物件型別,第二個為集合型別 第三個為關聯欄位以 如果關聯欄位不同 以被關聯物件的關聯欄位為準 這裡的deptno為dept物件中的管理欄位
String[] li={"EMPOBJ","EMPLIST","deptno"};
pr.execute(li, SQL);
}
// 測試儲存過程 新增多個型別入參
@Override
public void addLists(Emp emp, int w, List<Emp> list) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call ADDOBJ({2},{1},{3})}";
//如果想傳入一個物件進行新增必須在資料庫建立對應資料型別
//第一個為物件型別,第二個為集合型別 第三個為關聯欄位以 如果關聯欄位不同 以被關聯物件的關聯欄位為準 這裡的deptno為dept物件中的管理欄位
String[] li={"EMPOBJ","EMPLIST","deptno"};
String[] lis={"EMPOBJ","EMPLIST"};
List<String[]> arry=new ArrayList<String[]>();
arry.add(li);
arry.add(lis);
pr.execute(arry, SQL);
}
// 測試儲存過程 根據id獲取String型別
@Override
public String getNameById(int id) throws SQLException {
// TODO Auto-generated method stub
String sql="{call getname({1},{s})}";
return (String) pr.execute(sql).get(0);
}
// 測試儲存過程 根據id獲取Integer型別
@Override
public Integer getMgrById(int id) throws SQLException {
// TODO Auto-generated method stub
String sql="{call getmgr({1},{i})}";
return (Integer) pr.execute(sql).get(0);
}
// 測試儲存過程 根據id獲取double型別
@Override
public double getSalById(int id) throws SQLException {
// TODO Auto-generated method stub
String sql="{call getsal({1},{o})}";
return (double) pr.execute(sql).get(0);
}
// 測試儲存過程 根據id獲取DateE型別
@Override
public Date getHiredateById(int id) throws SQLException {
// TODO Auto-generated method stub
String sql="{call gethiredate({1},{d})}";
return (Date) pr.execute(sql).get(0);
}
}
這裡之所以用map集合是考慮到儲存過程可以輸出多個值的原因
而之所以結果集要傳入calss是因為考慮到過程可以輸出多個結果集的原因
第三步是我們要封裝一個入口啦也就是DAO所繼承的ProxyObjects類
package test.dao;
import java.sql.Connection;
import test.common.ProcessingCenter;
import test.common.utils.DBHelper;
//代理物件 名字隨便取都可以
public class ProxyObjects {
//處理中心物件
public ProcessingCenter pr;
//提供一個獲取Connection物件的方法 方法名稱一定為getCon
public Connection getCon(){
Connection con=DBHelper.getCon();
return con;
}
}
提供一個getcon方法這樣我們就可以將這個jar包和現在的主流框架一起使用了哈哈有木有很激動
第四部 我們最重要的處理中心
package test.dao.imp;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import qin.common.ProcessingCenter;
import test.DBHelper;
import test.bean.Dept;
import test.bean.Emp;
import test.dao.EmpDao;
import test.dao.ProxyObjects;
public class EmpDaoImpl extends ProxyObjects implements EmpDao {
/*
*數字代表傳入引數
*返回的是一個MAP集合 key(int)對應傳出引數的個數(按序)
*1代表普通型別 2代表物件型別 3代表集合型別
*
*字母代表傳出引數
*c代表遊標
*s代表String
*i代表Integer
*o代表double
*d代表data
*/
// 測試 sql 更具id獲取物件
@Override
public Emp finEmp(int id) throws Exception {
String SQL="select * from emp where empno=? ";
List<Emp> list = (List<Emp>) pr.executefindsql(SQL,Emp.class);
return list.get(0);
}
// 測試 sql 更新操作
@Override
public int updateEmp(String ename, int id) throws Exception {
// TODO Auto-generated method stub
String SQL = "update emp set ename = ? where empno = ?";
return pr.executeUpdatesql(SQL);
}
// 測試儲存過程 根據編號獲取物件
@Override
public Emp getEmpbyid(int id) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call getEmpbyid({1},{c})}";
Map<Integer, Object> map = pr.execute(SQL, Emp.class);
List<Emp> list = (List<Emp>) map.get(0);
return list.get(0);
}
// 測試儲存過程 根據編號 獲取集合
@Override
public List<Map<String, Object>> getListbyid(int id) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call getEmpbyid({1},{c})}";
return (List<Map<String, Object>>) pr.execute(SQL).get(0);
}
// 測試儲存過程 根據使用者名稱稱獲取物件集合
@Override
public List<Emp> getEmpListByEname(String ename) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call getEmpListByEname({1},{c})}";
Map<Integer, Object> execute = pr.execute(SQL,Emp.class);
return (List<Emp>) execute.get(0);
}
// 測試儲存過程 新增物件
@Override
public void addEmp(Emp emp) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call addEmp({2})}";
//如果想傳入一個物件進行新增必須在資料庫建立對應資料型別
//第一個為物件型別,第二個為集合型別 第三個為關聯欄位 如果關聯欄位不同 以被關聯物件的關聯欄位為準 這裡的deptno為dept物件中的管理欄位
String[] li={"EMPOBJ","EMPLIST","deptno"};
pr.execute(li, SQL);
}
// 測試儲存過程 新增集合
@Override
public void addEmps(List<Emp> list) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call addEmp({3})}";
//如果想傳入一個物件進行新增必須在資料庫建立對應資料型別
//第一個為物件型別,第二個為集合型別 第三個為關聯欄位以 如果關聯欄位不同 以被關聯物件的關聯欄位為準 這裡的deptno為dept物件中的管理欄位
String[] li={"EMPOBJ","EMPLIST","deptno"};
pr.execute(li, SQL);
}
// 測試儲存過程 新增多個型別入參
@Override
public void addLists(Emp emp, int w, List<Emp> list) throws SQLException {
// TODO Auto-generated method stub
String SQL="{call ADDOBJ({2},{1},{3})}";
//如果想傳入一個物件進行新增必須在資料庫建立對應資料型別
//第一個為物件型別,第二個為集合型別 第三個為關聯欄位以 如果關聯欄位不同 以被關聯物件的關聯欄位為準 這裡的deptno為dept物件中的管理欄位
String[] li={"EMPOBJ","EMPLIST","deptno"};
String[] lis={"EMPOBJ","EMPLIST"};
List<String[]> arry=new ArrayList<String[]>();
arry.add(li);
arry.add(lis);
pr.execute(arry, SQL);
}
// 測試儲存過程 根據id獲取String型別
@Override
public String getNameById(int id) throws SQLException {
// TODO Auto-generated method stub
String sql="{call getname({1},{s})}";
return (String) pr.execute(sql).get(0);
}
// 測試儲存過程 根據id獲取Integer型別
@Override
public Integer getMgrById(int id) throws SQLException {
// TODO Auto-generated method stub
String sql="{call getmgr({1},{i})}";
return (Integer) pr.execute(sql).get(0);
}
// 測試儲存過程 根據id獲取double型別
@Override
public double getSalById(int id) throws SQLException {
// TODO Auto-generated method stub
String sql="{call getsal({1},{o})}";
return (double) pr.execute(sql).get(0);
}
// 測試儲存過程 根據id獲取DateE型別
@Override
public Date getHiredateById(int id) throws SQLException {
// TODO Auto-generated method stub
String sql="{call gethiredate({1},{d})}";
return (Date) pr.execute(sql).get(0);
}
}
還有兩個附屬工具類 一個解析結果集的BeanUtils類和一個型別識別的列舉BataType類
首先是列舉BataType類
package test.common.utils;
public enum BataType {
//列舉型別
String("java.lang.String"),BigDecimal("java.math.BigDecimal"),Date("java.sql.Timestamp");
private String name;
//構造方法
private BataType(String name) {
this.name = name;
}
//根據name值獲取列舉型別
public static BataType getName(String name) {
for (BataType c : BataType .values()) {
if (c.name .equals(name)){
return c;
}
}
return null;
}
}
接著是解析結果集的BeanUtils物件
package qin.common.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class BeanUtils {
// 將結果集裝配進物件返回物件集合
public static List<Object> getBeans(ResultSet rs, Class<?> clazz) throws Exception {
// 返回的list集合
List<Object> list = new ArrayList<Object>();
// 定義一個map集合 String儲存物件和管理物件的屬性值 List儲存屬性的Field值以及所對應的物件
Map<String, List<Object>> map = new LinkedHashMap<String, List<Object>>();
// 屬性計數
int attrsCount = rs.getMetaData().getColumnCount();
int i = 1;
while (rs.next()) {
Object bean = clazz.newInstance();
Field[] prFields1 = clazz.getDeclaredFields();
// 返回 Field 物件的一個數組,這些物件反映此 Class物件所表示的類或介面所宣告的所有欄位。
// 儲存物件和關聯物件的屬性值Field值以及所對應的物件
for (Field field : prFields1) {
String firstLetter = field.getName().substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + field.getName().substring(1);
Method method = bean.getClass().getMethod(getter, null);
String a = method.getReturnType().toString().toLowerCase();
String s = a.substring(a.lastIndexOf(".") + 1);
// 如何相等當前屬性為關聯物件 所以bean命名要規範
if (s.equals(field.getName())) {
// 獲取空關聯物件
Object object = method.getReturnType().newInstance();
// 獲取管理物件的Field陣列
Field[] fields = method.getReturnType().getDeclaredFields();
for (Field field2 : fields) {
List<Object> lists = new ArrayList<Object>();
lists.add(field2);
lists.add(object);
lists.add(field);
map.put(field2.getName(), lists);
}
} else {
List<Object> lists = new ArrayList<Object>();
lists.add(field);
lists.add(bean);
map.put(field.getName(), lists);
}
}
// 解析結果集並寫入物件放入list集合
for (int j = 1; j <= attrsCount; j++) {
List<Object> list2 = map.get(rs.getMetaData().getColumnLabel(j).toLowerCase());
if (list2 == null) {
break;
}
//獲取當前屬性的field物件
Field field3 = (Field) list2.get(0);
field3.setAccessible(true);
//獲取當前寫入的bean物件
Object object = list2.get(1);
if (object == bean) {
// 獲取列舉型別進行型別匹配
BataType bataType = BataType.getName(rs.getMetaData().getColumnClassName(j));
switch (bataType) {
case String:
field3.set(object, rs.getString(j));
break;
case BigDecimal:
BigDecimal b = rs.getBigDecimal(j);
if (b != null) {
if (new BigDecimal(b.intValue()).compareTo(b) == 0) {
field3.set(object, rs.getInt(j));
} else {
field3.set(object, rs.getDouble(j));
}
}
break;
case Date:
field3.set(object, rs.getDate(j));
break;
}
} else {
BataType bataType = BataType.getName(rs.getMetaData().getColumnClassName(j));
switch (bataType) {
case String:
field3.set(object, rs.getString(j));
break;
case BigDecimal:
BigDecimal b = rs.getBigDecimal(j);
if (b != null) {
if (new BigDecimal(b.intValue()).compareTo(b) == 0) {
field3.set(object, rs.getInt(j));
} else {
field3.set(object, rs.getDouble(j));
}
}
break;
case Date:
field3.set(object, rs.getDate(j));
break;
}
Field Field4 = (Field) list2.get(2);
Field4.setAccessible(true);
Field4.set(bean, object);
}
}
list.add(bean);
}
return list;
}
// 將結果集裝配進 List<Map<String,Object>>並返回
public static List<Map<String,Object>> getBeans(ResultSet rs) throws Exception {
// 返回的list集合
List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
Map<String,Object> map=new HashMap<String,Object>();
// 屬性計數
int attrsCount = rs.getMetaData().getColumnCount();
while (rs.next()) {
for (int i = 1; i <= attrsCount; i++) {
// 每列給對應的屬性賦值
String attr = rs.getMetaData().getColumnLabel(i).toLowerCase();
map.put(attr, rs.getObject(i));
}
list.add(map);
}
return list;
}
}
最後就是我們的攔截器了
這裡我們用cglib動態代理實現AOP攔截
package test.common.proxy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import test.common.ProcessingCenter;
public class CglibProxy implements MethodInterceptor{
private Object target;
//生成代理物件
public Object getintercept(Object target){
this.target=target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
//切面邏輯 這個攔截器的目的是將目標物件的引數寫入資料處理中心(ProcessingCenter)並注入進目標物件
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
Class<?> superclass = target.getClass().getSuperclass();
Field field=superclass.getDeclaredField("pr");
ProcessingCenter re =new ProcessingCenter(args,superclass);
field.set(target, re);
Object ret;
ret=method.invoke(target, args);
return ret;
}
}
OK大功告成
不過還有一些型別沒戲 以後慢慢寫
常用的都已經寫了
接下來是儲存過程
create or replace procedure getEmpbyid (ids in number,O_RES OUT SYS_REFCURSOR)
as
begin
OPEN O_RES FOR
SELECT * from emp t left join dept d on t.deptno = d.deptno where t.empno= ids;
end;
create or replace procedure getEmpListByEname (ids in nvarchar2,O_RES OUT SYS_REFCURSOR)
as
begin
OPEN O_RES FOR
SELECT * from emp t left join dept d on t.deptno = d.deptno where t.ename= ids;
end;
--自定義物件型別
CREATE OR REPLACE TYPE EMPOBJ AS OBJECT (
EMPNO NUMBER(4),
ENAME NVARCHAR2(10),
JOB NVARCHAR2(9),
MGR NUMBER(4),
HIREDATE DATE,
SAL NUMBER(7,2),
COMM NUMBER(7,2),
DEPTNO NUMBER(2)
)
--自定義集合型別
CREATE OR REPLACE TYPE EMPLIST AS TABLE OF EMPOBJ
create or replace procedure addEmp(i_orders IN EMPLIST)
as
ctcOrder EMPOBJ:=i_orders(1);
begin
INSERT INTO EMP
(EMPNO, ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO)
VALUES
(ctcOrder.EMPNO,ctcOrder.ENAME,ctcOrder.JOB,ctcOrder.MGR,ctcOrder.HIREDATE,ctcOrder.SAL,ctcOrder.COMM, ctcOrder.DEPTNO);
exception when others then
raise;
end;
create or replace procedure getname (ids in number,namea out nvarchar2)
as
begin
SELECT ENAME into namea from emp where empno= ids;
end;
create or replace procedure getmgr (ids in number,mgr out number)
as
begin
SELECT MGR into mgr from emp where empno= ids;
end;
create or replace procedure getsal (ids in number,sals out number)
as
begin
SELECT SAL into sals from emp where empno= ids;
end;
create or replace procedure gethiredate (ids in number,hiredates out varchar2)
as
begin
SELECT HIREDATE into hiredates from emp where empno= ids;
end;
然後是我們的test測試
package test;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import qin.common.proxy.CglibProxy;
import test.bean.Emp;
import test.dao.EmpDao;
import test.dao.imp.EmpDaoImpl;
public class Test {
public static void main(String[] args) throws SQLException, Exception {
Emp emp = null;
// 獲取增強後的目標物件 ????
EmpDao dao = (EmpDao) new CglibProxy().getintercept(new EmpDaoImpl());
// 測試查詢sql String sql="select * from emp where empno=? ";
emp = dao.finEmp(7369);
System.out.println(emp);
// 測試更新sql String SQL = "update emp set ename = ? where empno = ?";
int updateEmp = dao.updateEmp("xiaohei", 1111);
System.out.println(updateEmp);
// 測試儲存過程 根據編號獲取物件
emp = dao.getEmpbyid(7369);
System.out.println(emp);
// 測試儲存過程 根據編號 獲取集合
List<Map<String, Object>> list = dao.getListbyid(7369);
System.out.println(list);
// 測試儲存過程 根據使用者名稱稱獲取物件集合 ????
List<Emp> empListByEname = dao.getEmpListByEname("SMITH");
System.out.println(empListByEname);
// 測試儲存過程 新增物件
emp.setEmpno(1224);
// dao.addEmp(emp);
// 測試儲存過程 新增集合
List<Emp> listEmp = new ArrayList<Emp>();
listEmp.add(emp);
// dao.addEmps(listEmp);
// 測試儲存過程 新增多個型別入參
// dao.addLists(emp, 1, listEmp);
// 測試儲存過程 根據id獲取String型別
String nameById = dao.getNameById(7369);
System.out.println(nameById);
// 測試儲存過程 根據id獲取Integer型別
Integer mgrById = dao.getMgrById(7369);
System.out.println(mgrById);
// 測試儲存過程 根據id獲取double型別
double salById = dao.getSalById(7369);
System.out.println(salById);
// 測試儲存過程 根據id獲取DateE型別
Date hiredateById = dao.getHiredateById(7369);
System.out.println(hiredateById);
}
}
看結果
在來看資料庫
想想以後呼叫儲存過程是多麼的簡單 一句話程式碼就可以啦
接下來將程式碼匯出為jar包 以後就可以直接匯入專案使用了