看看開源j2ee 架構bbossgroups 中的dbutil,batchutil 标簽來如何實作資料庫的 預編譯/普通insert , update , delete ,預編譯/普通批處理操作 ,比較簡單也比較使用。
文章分三部分介紹:
預編譯/普通insert , update , delete 操作
執行預編譯/普通批處理操作标簽
連接配接池配置
下面分别介紹。
[1] 預編譯/普通insert , update , delete 操作
1.1.1 Insert 操作
<%@ page contentType = "text/html; charset=GBK" language = "java" import = "java.sql.*,java.util.List" errorPage = "" %>
1.1.1.1 導入标簽定義檔案
<%@ taglib uri = "/WEB-INF/pager-taglib.tld" prefix = "pg" %>
<!--
dbutil 标簽實作 insert 操作
statement: 資料庫 insert 語句
dbname:insert 的相應資料庫名稱,在 poolman.xml 檔案中進行配置
-->
1.1.1.2 定義預編譯 sql 語句
<%
String object_id = "1" ;
String owner = "duoduo" ;
String object_name = "table_insert" ;
String created = "2010-03-12 16:52:10" ;
String last_ddl_time = "2010-03-12 16:52:11" ;
String sql = "insert into sqltest(object_id,owner,object_name,created,last_ddl_time) values(#[object_id],#[owner],#[object_name],#[created],#[last_ddl_time])" ;
%>
Sql 語句中的變量 #[object_id],#[owner],#[object_name],#[created],#[last_ddl_time]
的值和類型将在标簽 pg:sqlparam 中指定
< html >
< head >
< title > 測試在 dbutil 标簽上直接執行資料庫插入操作 </ title >
</ head >
< body >
< table >
1.1.1.3 Dbutil 執行預編譯插入操作
< pg:dbutil statement = "<%= sql %> "
dbname = "bspf"
pretoken = "#\\[" endtoken = "\\]"
action = "insert" >
statement 屬性指定了先前定義的預編譯插入語句
dbname 為資料庫連接配接池的名稱
pretoken = "#\\[" endtoken = "\\]" 分别指定了變量的分界符
action=insert 指定了本次執行的是 insert 操作。
1.1.1.4 指定各變量的值和類型
< pg:sqlparam name = "object_id" value = "<%= object_id %> " type = "int" />
< pg:sqlparam name = "owner" value = "<%= owner %> " type = "string" />
< pg:sqlparam name = "object_name" value = "<%= object_name %> " type = "string" />
< pg:sqlparam name = "created" value = "<%= created %> " type = "date" />
< pg:sqlparam name = "last_ddl_time" value = "<%= last_ddl_time %> " type = "timestamp" />
</ pg:dbutil >
<%= dbutil_result %>
Name 屬性指定變量的名稱,
Value 屬性指定變量的值
Type 屬性指定變量的類型,如果沒有指定那麼預設為字元串類型
dbutil_result 存放 insert 操作所插入的記錄數
</ table >
</ body >
</ html >
上面說明的是預編譯操作,要進行普通插入操作:
< pg:dbutil statement = "<%= sql %> "
</ pg:dbutil >
其中的 sql 為一條完成的插入語句即可。例如: insert into table ( name ) values(‘duoduo’) 。
1.1.2 update 操作
1.1.2.1 導入标簽定義檔案
dbutil 标簽實作 update 操作
statement: 資料庫 update 語句
dbname:update 的相應資料庫名稱,在 poolman.xml 檔案中進行配置
1.1.2.2 定義預編譯 sql 語句
String created = "2010-03-12 12:43:54" ;
String sql = "update sqltest set created=#[created] where object_id=#[object_id]" ;
Sql 語句中的變量 #[created], #[object_id] 的值和類型将在标簽 pg:sqlparam 中指定
< title > 測試在 dbutil 标簽上直接執行資料庫 update 操作 </ title >
1.1.2.3 Dbutil 執行預編譯修改操作
action = "update" >
statement 屬性指定了先前定義的預編譯 update 語句
action=update 指定了本次執行的是 update 操作。
1.1.2.4 指定各變量的值和類型
< pg:sqlparam name = "created" value = "<%= created %> " type = "timestamp" />
dbutil_result 存放 update 操作所修改的記錄數
上面說明的是預編譯操作,要進行普通 update 操作:
其中的 sql 為一條完整的 update 語句即可。例如: update table set name=‘duoduo’ 。
1.1.3 Delete 操作
1.1.3.1 導入标簽定義檔案
dbutil 标簽實作 delete 操作
statement: 資料庫查詢語句
dbname: delete 的相應資料庫名稱,在 poolman.xml 檔案中進行配置
1.1.3.2 定義預編譯 sql 語句
String object_id = "15" ;
String sql = "delete from sqltest where object_id=#[object_id] " ;
Sql 語句中的變量 #[object_id] 的值和類型将在标簽 pg:sqlparam 中指定
< title > 測試在 dbutil 标簽上直接執行資料庫 delete 操作 </ title >
1.1.3.3 Dbutil 執行預編譯 delete 操作
action = " delete" >
statement 屬性指定了先前定義的預編譯 delete 語句
action= delete 指定了本次執行的是 delete 操作。
1.1.3.4 指定各變量的值和類型
< pg:sqlparam name = "object_id" value = "<%= object_id %> " type = "int" />
dbutil_result 存放 delete 操作所删除記錄數
上面說明的是預編譯操作,要進行普通 delete 操作:
action = " delete" >
其中的 sql 為一條完整的 delete 語句即可。例如: delete frome table where name=‘duoduo’ 。
[2]執行預編譯/普通批處理操作标簽
相關的一組标簽:batchutil,statement,batch,sqlparam
通過這組标簽我們可以實作以下功能:
普通批處理操作
預編譯批處理操作
下面詳細說明上述功能。
1.1.1 普通批處理操作
<%@ page contentType="text/html; charset=GBK" language="java"%>
1.1.1.1 導入标簽定義檔案
<%@ taglib uri="/WEB-INF/pager-taglib.tld" prefix="pg"%>
batchutil标簽實作資料庫批處理操作
statement:指定批處理語句
dbname:批處理語句執行的對應的資料庫連接配接池名稱,在poolman.xml檔案中進行配置
-->
1.1.1.2 定義一組要進行批處理操作的sql語句
<% String sql = "update sqltest set batch='1' where object_id=1";
String sql1 = "update sqltest set batch='2' where object_id=1";
String sql2 = "update sqltest set batch='3' where object_id=1";
String sql3 = "update sqltest set batch='4' where object_id=1";
String sql4 = "update sqltest set batch='5' where object_id=1";
%>
<html>
<head>
<title>測試在batchutil标簽上直接執行資料庫批處理操作</title>
</head>
<body>
<table>
1.1.1.3 使用batchutil标簽執行批處理操作
<pg:batchutil dbname="bspf" type="common">
<pg:statement sql="<%=sql %>" />
<pg:statement sql="<%=sql1 %>" />
<pg:statement sql="<%=sql2 %>" />
<pg:statement sql="<%=sql3 %>" />
<pg:statement sql="<%=sql4 %>" />
</pg:batchutil>
</table>
</body>
</html>
1.1.2 預編譯批處理操作
1.1.2.1 導入标簽定義檔案
batchutil标簽實作資料庫預編譯批處理操作
statement:指定預編譯批處理語句
dbname:預編譯批處理語句執行的對應的資料庫連接配接池名稱,在poolman.xml檔案中進行配置
1.1.2.2 定義一組要進行預編譯批處理操作的sql語句和參數組
預編譯批處理操作可以是多條不同的預編譯sql語句,也可以是同一條sql語句的多個不同的綁定變量參數組,也可以是混合的情況。下面我們使用一條sql語句和5組不同的綁定參數的情況做為示例來說明各種不同的情況。
<%
String object_id = "1";
String created = "2010-03-12 12:43:54";
String created1 = "2010-03-13 12:43:54";
String created2 = "2010-03-14 12:43:54";
String created3 = "2010-03-15 12:43:54";
String created4 = "2010-03-16 12:43:54";
String sql = "update sqltest set created=#[created] where object_id=#[object_id]";
<title>測試在batchutil标簽上直接執行資料庫預編譯批處理操作</title>
1.1.2.3 使用batchutil标簽執行預編譯批處理操作
<pg:batchutil dbname="bspf" type="prepared">
<pg:statement sql="<%=sql %>" pretoken="#\\[" endtoken="\\]">
1.1.2.3.1 多組不同的參數用batch标簽來組織
<pg:batch>
<pg:sqlparam name="object_id" value="<%=object_id %>" type="int" />
<pg:sqlparam name="created" value="<%=created %>" type="timestamp" />
</pg:batch>
</pg:statement>
<pg:sqlparam name="created" value="<%=created1 %>"
type="timestamp" />
1.1.2.3.2 如果隻有一組參數,那麼不需要使用batch标簽
<pg:sqlparam name="object_id" value="<%=object_id %>" type="int" />
<pg:sqlparam name="created" value="<%=created2 %>" type="timestamp" />
<pg:sqlparam name="created" value="<%=created3 %>"
<pg:sqlparam name="created" value="<%=created4 %>"
如果要引入事務的話,可以在執行sql的标簽代碼的外圍包一個事務即可使用的方法如下:
import com.frameworkset.orm.transaction.TransactionManager;
TransactionManager tm = new TransactionManager();
try
{
tm.begin();//開始事務
%>
放置操作資料庫的标簽代碼
<%
tm.commit();//送出事務
}
catch(Exception e)
try {
tm.rollback();//復原事務
} catch (Exception e1) {
e1.printStackTrace();
}
%>
[3]連接配接池配置
概述
bboss persistent的配置檔案為poolman.xml,位于classes目錄下即可
1.bboss persistent架構支援多個資料源配置
2.bboss persistent架構預設采用apache common dbcp作為資料庫連接配接池
3.bboss persistent架構可以引用外部資料源,例如tomcat,weblogic和WebSphere平台提供的datasource
基本配置執行個體,隻配置了一個datasource,如果需要配置多個datasource,隻需要按照相應格式再加資料源就可以了:
<?xml version="1.0" encoding="gb2312"?>
<poolman>
<datasource>
<!--
連接配接池的邏輯名稱,
應用程式通過該名稱擷取對應的資料庫連接配接池的連結
持久層接口通過指定該名稱在相應的資料庫上執行增删改查操作
import java.sql.Connection;
import java.sql.SQLException;
import com.frameworkset.common.poolman.DBUtil;
.....
Connection con = DBUtil.getConection(“bspf”);
-->
<dbname>bspf</dbname>
<!--
資料庫連結池啟動時是否加載資料庫表和視圖的中繼資料 ,應用程式可以調用以下接口擷取這些資料:
import com.frameworkset.common.poolman.DBUtil;
import com.frameworkset.common.poolman.sql.TableMetaData;
TableMetaData tableMetaData = DBUtil.getTableMetaData("V_VCH_FIXED_TAX_CF");
System.out.println(DBUtil.getTableMetaData("V_VCH_FIXED_TAX_CF"));
-->
<loadmetadata>false</loadmetadata>
datasource的jndi查找名稱,如果指定了jndiName參數
bboss persistent架構将連結池綁定為datasource,應用程式可以通過
jndi查找擷取資料庫連結,例如:
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("bspf_datasource_jndiname");
-->
<jndiName>bspf_datasource_jndiname</jndiName>
autoprimarykey
true表示啟用insert自動補全功能,如果在insert sql語句中沒有指定主鍵字段,那麼bboss persistent将自動補全該條語句
首先分析sql語句得到table name,然後根據該表名到tableinfo表中查找表的主鍵資訊,找到後根據主鍵配置生成一個主鍵,補全到sql語句中
當執行插入操作的方法時,該主鍵将作為方法的傳回值傳回給調用程式。
false表示不自動生成,預設值,這樣避免分析sql語句,提高系統性能。
<autoprimarykey>false</autoprimarykey>
<!--
cachequerymetadata 是否緩沖查詢語句中查詢清單中的字段資訊
true表示緩沖,提高系統新能,一旦系統記憶體不夠時,将自動釋放這些緩沖
false,表示不緩沖
<cachequerymetadata>false</cachequerymetadata>
driver 指定資料庫驅動程式
<driver>oracle.jdbc.driver.OracleDriver</driver>
url 指定資料庫連接配接串
<url>jdbc:oracle:thin:@//localhost:1521/orcl</url>
<!--
username 指定資料庫使用者
<username>cmsnew</username>
password 指定資料庫使用者密碼
<password>cmsnew</password>
txIsolationLevel 指定資料庫事務隔離級别
<txIsolationLevel>READ_COMMITTED</txIsolationLevel>
initialConnections 指定資料庫連接配接池初始連接配接數
<initialConnections>2</initialConnections>
minimumSize 指定資料庫連接配接池最小連接配接數
<minimumSize>2</minimumSize>
maximumSize 指定資料庫連接配接池最大連接配接數
<maximumSize>8</maximumSize>
<!--控制connection達到maximumSize是否允許再建立新的connection
true:允許,預設值
false:不允許-->
<maximumSoft>false</maximumSoft>
是否檢測逾時連結(事務逾時連結),當資料庫連接配接資源不夠時,才會檢測,否則不檢測
true-檢測,如果檢測到有事務逾時的連結,系統将強制回收(釋放)該連結
false-不檢測,預設值
-->
<removeAbandoned>true</removeAbandoned>
<!--
連結使用逾時時間(事務逾時時間)
機關:秒
<userTimeout>120</userTimeout>
系統強制回收連結時,是否輸出背景日志
true-輸出,預設值
false-不輸出
<logAbandoned>true</logAbandoned>
資料庫會話是否是readonly,預設為false
<readOnly>true</readOnly>
對應屬性:timeBetweenEvictionRunsMillis
the amount of time (in seconds) to sleep between examining idle objects for eviction
空閑連結逾時檢測處理啟動間隔時間
<skimmerFrequency>86400</skimmerFrequency>
<!--對應于minEvictableIdleTimeMillis 屬性:
minEvictableIdleTimeMillis the minimum number of milliseconds
an object can sit idle in the pool before it is eligable for evcition
機關:秒
空閑連結回收時間,空閑時間超過指定的值時,将被回收
<connectionTimeout>120</connectionTimeout>
numTestsPerEvictionRun
the number of idle objects to
examine per run within the idle object eviction thread (if any)
每次檢測時,檢測的空閑連結個數 ,為零時檢測所有的空閑連結
<shrinkBy>4</shrinkBy>
<!--
/**
* 檢測空閑連結處理時,是否對空閑連結進行有效性檢查控制開關
* true-檢查,都檢查到有無效連結時,直接銷毀無效連結
* false-不檢查,預設值
*/
<testWhileidle>false</testWhileidle>
(1) 在tableinfo表中配置了sequence時,以下機制不起作用,
定義資料庫主鍵生成機制
預設的采用系統自帶的主鍵生成機制,
外步程式可以覆寫系統主鍵生成機制
由值來決定
auto:自動,一般在生産環境下采用該種模式,
解決了單個應用并發通路資料庫添加記錄産生沖突的問題,效率高,如果生産環境下有多個應用并發通路同一資料庫時,必須采用composite模式
composite:結合自動和實時從資料庫中擷取最大的主鍵值兩種方式來處理,開發環境下建議采用該種模式,
解決了多個應用同時通路資料庫添加記錄時産生沖突的問題,效率相對較低, 如果生産環境下有多個應用并發通路同一資料庫時,必須采用composite模式
(2)通過以下方法擷取主鍵
DBUtil中的下述方法擷取主鍵
DBUtil.getNextPrimaryKey(Connection, tablename)
DBUtil.getNextPrimaryKey(Connection, dbname, tablename)
DBUtil.getNextPrimaryKey(tablename)
DBUtil.getNextPrimaryKey(dbname, tablename)
DBUtil.getNextStringPrimaryKey(Connection, tablename)
DBUtil.getNextStringPrimaryKey(Connection, dbname, tablename)
DBUtil.getNextStringPrimaryKey(tablename)
DBUtil.getNextStringPrimaryKey(dbname, tablename)
前提是tablename對應的表的主鍵資訊必須配置在tableinfo表中,tableinfo表的結構為:
名稱 是否為空? 類型 描述
----------------------------------------- -------- ----------------------------
TABLE_NAME NOT NULL VARCHAR2(255) 表名稱
TABLE_ID_NAME VARCHAR2(255) 表的主鍵名稱
TABLE_ID_INCREMENT NUMBER(5) 表主鍵的自增值
TABLE_ID_VALUE NUMBER(20) 表主鍵目前值,已經不使用
TABLE_ID_GENERATOR VARCHAR2(255) 表主鍵生成機制,隻有TABLE_ID_TYPE為sequence時才需填為相應sequence的名稱
TABLE_ID_TYPE VARCHAR2(255) 表主鍵的數值類型,int,long,string,sequence,如果為sequence時必須指定TABLE_ID_GENERATOR為對應的sequence的名稱
TABLE_ID_PREFIX VARCHAR2(255) 為表主鍵添加統一的字首,預設為null,隻有表主鍵類型為string時才能指定字首。
<keygenerate>composite</keygenerate>
<!-- 請求連結時等待時間,機關:秒
客服端程式請求連結等待時間,超過指定值時背景包報待逾時異常
<maxWait>10</maxWait>
連結有效性檢查sql語句
<validationQuery>select 1 from dual</validationQuery>
<!-- 如果在tableinfo表中配置了表的主鍵資訊,而且主鍵通過sequence生成,則synsequence元素
用來控制是否同步sequence的目前值為最大的未使用的表的主鍵值+1。
<synsequence>false</synsequence>
<!-- 每個connection預編譯statement池化标記
true:池化
false:不池化,預設值
<poolingPreparedStatements>false</poolingPreparedStatements>
每個connection最大打開的預編譯statements數-1
<maxOpenPreparedStatements>-1</maxOpenPreparedStatements>
設定為true,則相關的增删改查,批處理,預編譯處理,存儲函數調用sql語句将全部被輸出的系統背景
否則不輸出
<showsql>true</showsql>
</datasource>
</poolman>
外部資料源執行個體
<datasource external=“true”>
...
<!--
當dataSource的external屬性指定為true時,必須指定外部資料源jndi綁定名稱
如果系統需要通過内部的jndi查找該資料源,還必須指定jndiName名稱,比如系統管理中hibernate
必需通過内部jndi通路資料源來擷取資料庫的連結,以及應用hibernate産生自定義資料庫主鍵機制
<externaljndiName>external_bspf_datasource_jndiname</externaljndiName>
driver 指定資料庫驅動程式,外部資料源需要指定資料庫的驅動程式是為了識别不同類型的資料庫
<!-- 如果在tableinfo表中配置了表的主鍵資訊,而且主鍵通過sequence生成,則synsequence元素
設定為true,則相關的增删改查,批處理,預編譯處理,存儲函數調用sql語句将全部被輸出的系統背景