
2008年2月12日
CJDBC官網(wǎng)http://c-jdbc.ow2.org/
cjdbc與hibernate的整合
Configuring C-JDBC with Hibernate
C-JDBC just has to be defined as any JDBC driver in Hibernate, leaving the syntax set to the proper database. Here is a configuration example to use Hibernate with a C-JDBC cluster made of Sybase backends:
## C-JDBC
hibernate.dialect net.sf.hibernate.dialect.SybaseDialect
hibernate.connection.driver_class org.objectweb.cjdbc.driver.Driver
hibernate.connection.username user
hibernate.connection.password pass
hibernate.connection.url jdbc:cjdbc://localhost:25322/test
轉(zhuǎn)自:http://lzj0470.javaeye.com/blog/445348
一、前言 |
cjdbc ( http://c-jdbc.objectweb.org/ ) 是一個(gè)open source的數(shù)據(jù)庫(kù)集群中間件,任何基于jdbc的應(yīng)用都可以通過(guò)它透明地訪問(wèn)數(shù)據(jù)庫(kù)集群,它可以進(jìn)行各個(gè)節(jié)點(diǎn)之間的數(shù)據(jù)復(fù)制,并且可以實(shí)現(xiàn)各個(gè)節(jié)點(diǎn)的查詢(xún)負(fù)載均衡。通過(guò)這樣的軟件,偶們可以方便的實(shí)現(xiàn)RAIDb - Redundant Array of Inexpensive Database 廉價(jià)數(shù)據(jù)庫(kù)冗余陣列。
大型應(yīng)用隨著用戶(hù)量訪問(wèn)越來(lái)越大,增加數(shù)據(jù)庫(kù)存儲(chǔ)和做好數(shù)據(jù)庫(kù)冗余可以增加系統(tǒng)的可靠性和性能。
下面利用cjdbc,把兩臺(tái)對(duì)等的 Mysql 做 RAIDb,本文假定你已經(jīng)搭建好兩臺(tái)對(duì)等的 Mysql環(huán)境并建好一個(gè)需要做集群冗余的數(shù)據(jù)庫(kù) clusterdb。 |
|
二、配置環(huán)境 |
Mysql: 5.0.19, 并使用 InnoDB 作為 Mysql 引擎
C-jdbc: 2.0.2
Jdk: 1.5 |
|
三、選擇合適的 C-JDBC RAIDb 機(jī)制 |
cjdbc有幾種RAIDb的機(jī)制可以選擇,如RAIDb-0,RAIDb-1等等,可以根據(jù)不同的情況選擇不同的RAIDb的機(jī)制。各種 RAIDb的機(jī)制詳情請(qǐng)查看 cjdbc 的文檔和 Demo。
RAIDb-1有如下功能:
完全鏡像處理機(jī)制,每個(gè)節(jié)點(diǎn)上都有完整的數(shù)據(jù)庫(kù)結(jié)構(gòu),這種方式提供了最好的容錯(cuò)處理,并且通過(guò)設(shè)置合理的Loading Balance策略,可以帶來(lái)查詢(xún)性能相當(dāng)好的提高。但是由于對(duì)于任何的寫(xiě)操作(create/update/delete),需要在各個(gè)節(jié)點(diǎn)上進(jìn)行傳播復(fù)制,寫(xiě)操作就會(huì)比原來(lái)慢一些了,如下圖:

這里選擇 RAIDb-1 做為 cjdbc RAIDb 機(jī)制。
|
|
四、給兩臺(tái)對(duì)等的 Mysql 建表,假設(shè)兩臺(tái) Mysql 的IP分別是 192.168.0.2和192.168.0.3 |
bash> mysql -h192.168.0.2 -uroot
bash> use clusterdb
bash> create table user (id int(3) not null auto_increment primary key, name char(50) not null) engine innodb;
bash> exit;
bash> mysql -h192.168.0.3 -uroot
bash> use clusterdb
bash> create table user (id int(3) not null auto_increment primary key, name char(50) not null) engine innodb;
bash> exit; |
|
五、在 Linux 下安裝 C-JDBC Controller |
bash> mkdir -p /usr/local/c-jdbc
bash> cd /usr/local/c-jdbc
bash> tar xvfz c-jdbc-2.0.2-bin.tar.gz
bash> export CJDBC_HOME=/usr/local/c-jdbc
|
|
六、把 Mysql JDBC Driver 放到 C-JDBC Controller 中來(lái) |
這里我們使用 mysql-connector-java-3.1.12-bin.jar 驅(qū)動(dòng)程序,把它放到
/usr/local/c-jdbc/drivers 中
|
|
七、配置 C-JDBC Controller |
1、在 /usr/local/c-jdbc/config/virtualdatabase 目錄中創(chuàng)建 虛擬數(shù)據(jù)庫(kù)配置文件,并把它命名為 mysql-raidb1-distribution.xml,內(nèi)容如下:
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE C-JDBC PUBLIC "-//ObjectWeb//DTD C-JDBC 2.0.2//EN" "http://c-jdbc.objectweb.org/dtds/c-jdbc-2.0.2.dtd">
<C-JDBC>
<VirtualDatabase name="myDB">
<Distribution>
</Distribution>
<AuthenticationManager>
<Admin>
<User username="admin" password="c-jdbc"/>
</Admin>
<VirtualUsers>
<VirtualLogin vLogin="boss" vPassword="boss"/>
</VirtualUsers>
</AuthenticationManager>
<DatabaseBackend name="mysqlNode211" driver="org.gjt.mm.mysql.Driver" url="jdbc:mysql://192.168.0.2/clusterdb" connectionTestStatement="select 1">
<ConnectionManager vLogin="boss" rLogin="boss_user" rPassword="123456">
<VariablePoolConnectionManager initPoolSize="10" minPoolSize="10" maxPoolSize="50" idleTimeout="30" waitTimeout="10"/>
</ConnectionManager>
</DatabaseBackend>
<DatabaseBackend name="mysqlNode213" driver="org.gjt.mm.mysql.Driver" url="jdbc:mysql://192.168.0.3/clusterdb" connectionTestStatement="select 1">
<ConnectionManager vLogin="boss" rLogin="boss_user" rPassword="123456">
<VariablePoolConnectionManager initPoolSize="10" minPoolSize="10" maxPoolSize="50" idleTimeout="30" waitTimeout="10"/>
</ConnectionManager>
</DatabaseBackend>
<RequestManager>
<RequestScheduler>
<RAIDb-1Scheduler level="passThrough"/>
</RequestScheduler>
<LoadBalancer>
<RAIDb-1>
<WaitForCompletion policy="first"/>
<RAIDb-1-LeastPendingRequestsFirst/>
</RAIDb-1>
</LoadBalancer>
</RequestManager>
</VirtualDatabase>
</C-JDBC>
|
2、在 /usr/local/c-jdbc/config/controller 目錄中創(chuàng)建 C-JDBC controller 配置文件,并把它命名為 uud-controller-distributed.xml,內(nèi)容如下:
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE C-JDBC-CONTROLLER PUBLIC "-//ObjectWeb//DTD C-JDBC-CONTROLLER 2.0.2//EN" "http://c-jdbc.objectweb.org/dtds/c-jdbc-controller-2.0.2.dtd">
<C-JDBC-CONTROLLER>
<Controller port="25323">
<JmxSettings>
<RmiJmxAdaptor port="1091"/>
</JmxSettings>
<VirtualDatabase configFile="mysql-raidb1-distribution.xml" virtualDatabaseName="myDB" autoEnableBackends="true"/>
</Controller>
</C-JDBC-CONTROLLER>
|
3、在 /usr/local/c-jdbc/config/demo 目錄中創(chuàng)建啟動(dòng) C-JDBC controller sh,并把它命名為 uud-distributed-raidb1-controller.sh,內(nèi)容如下:
#!/bin/sh
export CJDBC_HOME=/usr/local/c-jdbc
export JAVA_HOME=/opt/jdk1.5
cd $CJDBC_HOME/bin
echo "Waiting for mysql servers to finish start up"
echo "Starting Controller"
./controller.sh -f ../config/controller/uud-controller-distributed.xml &
|
|
|
八、啟動(dòng) C-JDBC Controller |
bash> cd /usr/local/c-jdbc/demo
bash> chmod u+rwx uud-distributed-raidb1-controller.sh
bash> ./uud-distributed-raidb1-controller.sh &
如果啟動(dòng)正常,顯示的信息如下:
Waiting for mysql servers to finish start up
Starting Controller
2006-04-20 10:32:21,126 INFO controller.core.Controller C-JDBC controller (2.0.2)
2006-04-20 10:32:21,189 INFO controller.core.Controller Loading configuration file: ../config/controller/uud-controller-distributed.xml
2006-04-20 10:32:21,278 INFO controller.core.Controller JMX is enabled
2006-04-20 10:32:21,308 INFO controller.core.Controller Starting JMX server on host: 127.0.0.1
2006-04-20 10:32:21,674 INFO backend.DatabaseBackend.mysqlNode211 Adding connection manager for virtual user "boss"
2006-04-20 10:32:21,749 INFO backend.DatabaseBackend.mysqlNode213 Adding connection manager for virtual user "boss"
2006-04-20 10:32:21,809 INFO controller.RequestManager.myDB Request manager will parse requests with the following granularity: NO_PARSING
2006-04-20 10:32:21,814 INFO controller.virtualdatabase.myDB Configuring jgroups using: file:/usr/local/c-jdbc/config/jgroups.xml
-------------------------------------------------------
GMS: address is 127.0.0.1:32773
-------------------------------------------------------
2006-04-20 10:32:26,476 INFO controller.virtualdatabase.myDB Group myDB connected to /127.0.0.1:32773[/127.0.0.1:32773]
2006-04-20 10:32:26,476 INFO controller.virtualdatabase.myDB First controller in group myDB
2006-04-20 10:32:26,477 WARN controller.virtualdatabase.myDB No recovery log has been configured, enabling backend without checkpoint.
[1]+ Done ./uud-distributed-raidb1-controller.sh
|
|
|
八、編寫(xiě) C-JDBC 客戶(hù)端程序 |
1、把 C-JDBC Drivers(/usr/local/c-jdbc/drivers/c-jdbc-driver.jar) 放置到 CLASSPATH 中
2、編寫(xiě)插入 10 條數(shù)據(jù)到 Mysql 中,程序如下:
/**
* @author 胡榮華
* @Company 世紀(jì)龍 21cn
*/
package com.cjdbc.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.DriverManager;
/**
*
*/
public class GenerateSampleData {
public void generate() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
// 這是 c-jdbc drivers 的 Drivers class,注意不是 mysql 的 Drivers class
Class.forName("org.objectweb.cjdbc.driver.Driver").newInstance();
// 192.168.0.1 是 cjdbc controller 所在的 ip
// myDB 是在 文件 mysql-raidb1-distribution.xml 里定義的 <VirtualDatabase name="myDB">
// user=boss&password=boss 是在 文件 mysql-raidb1-distribution.xml 里定義的
// <VirtualUsers>
// <VirtualLogin vLogin="boss" vPassword="boss"/>
// </VirtualUsers>
String url = "jdbc:cjdbc://192.168.0.1:25323/myDB?user=boss&password=boss";
conn = DriverManager.getConnection(url);
try{
conn.setAutoCommit(false);
pstmt = conn.prepareStatement("insert into user values ('', ?)");
int numOfTestRecords = 10;
System.out.println("Update Record Start.");
for (int i=0;i<numOfTestRecords;i++) {
String newkey = i + "-" + i;
pstmt.setString(1, "hua_" + newkey);
pstmt.executeUpdate();
}
conn.commit();
System.out.println("Update Record Success.");
}
catch(Exception ex){
conn.rollback();
ex.printStackTrace();
}
finally{
try {
if( pstmt != null )
pstmt.close();
if( conn != null)
conn.close();
}
catch(Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
GenerateSampleData g = new GenerateSampleData();
g.generate();
}
}
|
3、程序執(zhí)行完畢后,分別到 Mysql Node 192.168.0.2 和 192.168.0.3 查詢(xún),看看是否已同步了數(shù)據(jù),如果兩個(gè) Mysql Node 都有相同的數(shù)據(jù),說(shuō)明 C-JDBC 環(huán)境搭建成功。
|
|
最近做了一個(gè)日志管理系統(tǒng)
個(gè)人覺(jué)得采用了一套非常非常創(chuàng)新或者變態(tài)的開(kāi)發(fā)方式,就像題目說(shuō)的那樣,使用web的方法開(kāi)發(fā)桌面應(yīng)用程序,當(dāng)然所有的技術(shù)都是基于java的。
總結(jié)一下在整個(gè)項(xiàng)目中使用到的技術(shù)
1、底層服務(wù)器的開(kāi)發(fā)socket通信、http報(bào)文解析、反射機(jī)制(這些技術(shù)其實(shí)就是開(kāi)發(fā)了一款小型的服務(wù)器,讓我們的web代碼能夠在本地運(yùn)行起來(lái),之所以選擇自己開(kāi)發(fā)服務(wù)器的原因是,tomcat對(duì)于我們這個(gè)小桌面程序來(lái)說(shuō)還是太大了點(diǎn),如果作為桌面啟動(dòng),用戶(hù)不可能等待程序啟動(dòng)這么長(zhǎng)的時(shí)間,我給這個(gè)服務(wù)器起了個(gè)名字叫做jnet)
2、SWT,包括的瀏覽器控件和窗口等。
3、使用installanywhere來(lái)打包程序,方便發(fā)布
4、前臺(tái)展現(xiàn)數(shù)據(jù)使用了ext2.2
5、擴(kuò)展自己開(kāi)發(fā)的服務(wù)器jnet,開(kāi)發(fā)出自己的“action”,應(yīng)該來(lái)說(shuō)還是符合MVC的
數(shù)據(jù)庫(kù)使用的是access,采用jdbc的方式訪問(wèn),你知道,如果在桌面軟件上使用hibernate...
好了,不說(shuō)廢話(huà)
先貼出成品的效果圖
1、桌面圖標(biāo)

2、登錄界面

3、登錄效果圖

4、主界面

是不是覺(jué)得還不錯(cuò)呢?JAVA也可以揚(yáng)眉吐氣開(kāi)發(fā)出這樣的桌面系統(tǒng),可惜的是因?yàn)槭褂玫搅薙WT,所以整個(gè)項(xiàng)目并不能跨平臺(tái),放到linux系統(tǒng)下去運(yùn)行。
好了先理一理,發(fā)一張項(xiàng)目的原理圖

看圖說(shuō)話(huà),我們整個(gè)項(xiàng)目的構(gòu)架,就是這個(gè)樣子的,采用SWT封裝了IE作為前臺(tái)展現(xiàn),后臺(tái)使用自己開(kāi)發(fā)的服務(wù)器作為后臺(tái)來(lái)處理數(shù)據(jù),中間數(shù)據(jù)通信方式當(dāng)然就只能是http了
所以中心思想就是,我開(kāi)發(fā)了個(gè)服務(wù)器,這個(gè)服務(wù)器能夠讓用戶(hù)擴(kuò)展自己的類(lèi),自己的方法,然后用戶(hù)就可以根據(jù)自己的需要來(lái)書(shū)寫(xiě)自己的系統(tǒng),最最最重要的就是,讓我們這些寫(xiě)慣了J2EE的人能夠使用已經(jīng)形成的思維來(lái)編寫(xiě)桌面系統(tǒng),我們可以不需要再去學(xué)swing和swt,可以使用html的方式來(lái)做前臺(tái)的布局,因?yàn)槔蠈?shí)說(shuō)我每次寫(xiě)桌面程序的時(shí)候,總會(huì)把代碼弄得一團(tuán)糟,在web系統(tǒng)上容易規(guī)規(guī)矩矩的寫(xiě)出分層的代碼,桌面系統(tǒng)...布局就讓我頭大(我的意思是當(dāng)你跑出去接私活干的時(shí)候,不用再學(xué)一套東西,呵呵)。
好了,這個(gè)帖子只是一個(gè)簡(jiǎn)單的介紹,整個(gè)系統(tǒng)具體的實(shí)現(xiàn)方式,會(huì)在后續(xù)的帖子中一步步解析,大家有什么意見(jiàn)或者建議可以給我留言,謝謝!
開(kāi)發(fā)的時(shí)候有時(shí)候會(huì)碰到這樣的情況,我們?cè)趯?xiě)程序的時(shí)候并不知道需要調(diào)用某個(gè)對(duì)象的哪個(gè)方法,只有程序運(yùn)行后,我們才能夠知道。或許我們需要根據(jù)客戶(hù)端傳過(guò)來(lái)的某個(gè)String參數(shù)的值來(lái)判斷我們應(yīng)該執(zhí)行哪個(gè)方法。在這種情況下JAVA的反射執(zhí)行就可以幫上忙了。下面是我做的一個(gè)簡(jiǎn)單的測(cè)試代碼,提供給大家做個(gè)參考。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


/** *//**
* @author Dong
* 測(cè)試JAVA reflect機(jī)制
*/

public class TestRef
{

/** *//**
* @param args
*/

public static void main(String[] args)
{
TestBean test = new TestBean();
Method[] methods = test.getClass().getMethods();
test.setAbc("---");

for(int i=0;i<methods.length;i++)
{

if(methods[i].getName().equalsIgnoreCase("getabc"))
{

try
{
System.out.println(methods[i].invoke(test));

} catch (IllegalArgumentException e)
{
e.printStackTrace();

} catch (IllegalAccessException e)
{
e.printStackTrace();

} catch (InvocationTargetException e)
{
e.printStackTrace();
}
}
}
}
}

(String[])ArrayList.toArray(new String[0]);
XML里是無(wú)法直接正常輸出&等特殊字符的,可用&轉(zhuǎn)義表示!
1、數(shù)字格式化
<fmt:formatNumber value="33.33333" pattern="#.0"></fmt:formatNumber>-->輸出33.3
pattern中符號(hào)的約束規(guī)定
0 一個(gè)數(shù)位
# 一個(gè)數(shù)位,前導(dǎo)零和追尾零不顯示
. 小數(shù)點(diǎn)分割位置
, 組分隔符的位置
- 負(fù)數(shù)前綴
% 用100乘,并顯示百分號(hào)
其他任何符號(hào) 在輸出字符串中包括指定符號(hào)
2、日期格式化
<fmt:formatDate value="${vo.lateCompleteDate}" type="both" pattern="yy-MM-dd"/>
HashMap<String,String> testMap = new HashMap<String,String>();
for (Map.Entry<String, String> entry : testMap .entrySet()) {
entry.getKey();
entry.getValue();
}
ApplicationContext ctx = new ClassPathXmlApplicationContext("application-config.xml");
Map<String,String> bureauMap = ((DictionaryService)ctx.getBean("dictionaryService")).getBureauMap();
今天在調(diào)試一個(gè)Servlet程序的時(shí)候,報(bào)了以下錯(cuò)誤!
java.lang.IllegalStateException: Cannot forward after response has been committed
根據(jù)字面理解的話(huà),意識(shí)是在response已經(jīng)提交后程序不能再一次的跳轉(zhuǎn)!
研究代碼以后發(fā)現(xiàn),是因?yàn)榍懊嬉呀?jīng)執(zhí)行過(guò)一次request.request.getRequestDispatcher().forward()
但是后面的request.request.getRequestDispatcher().forward()依然被執(zhí)行到了!
那么很有理由相信request.request.getRequestDispatcher().forward()跳轉(zhuǎn)本身是不會(huì)返回什么,也不會(huì)終止程序體的執(zhí)行!
程序體后面該執(zhí)行的還是會(huì)執(zhí)行!
<Resource name="jdbc/dong" auth="Container" type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/dong">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
<parameter>
<name>username</name>
<value>root</value>
</parameter>
<parameter>
<name>password</name>
<value>colorful</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>org.gjt.mm.mysql.Driver</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:mysql://localhost:3306/dong</value>
</parameter>
</ResourceParams>

使用如上配置的時(shí)候一直報(bào)這個(gè)
org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'錯(cuò)誤
在網(wǎng)絡(luò)上尋覓后發(fā)現(xiàn)是因?yàn)門(mén)omcat版本引起的,改成如下問(wèn)題就消失了
<Resource
name="jdbc/dong"
type="javax.sql.DataSource"
password="colorful"
driverClassName="org.gjt.mm.mysql.Driver"
maxIdle="2"
maxWait="5000"
username="root"
url="jdbc:mysql://localhost:3306/dong"
maxActive="4"/>
1、 解決Action過(guò)多問(wèn)題
通過(guò)DispatchAction的方式
建立一個(gè)繼承自DispatchAction的Action
此類(lèi)Action允許我們?cè)诒韱沃袔в袇?shù),根據(jù)參數(shù)執(zhí)行Action中的不同方法,以此實(shí)現(xiàn)Action的多用
步驟
① 建立一個(gè)繼承自DispatchAction的Action規(guī)定方法名稱(chēng)
② 在表單頁(yè)面中添加一個(gè)隱藏域值,假設(shè)為codi value=”insert”
③ 在Struts-config.xml的相應(yīng)Form中action項(xiàng)目中設(shè)置parameter參數(shù)值為codi
那么當(dāng)表單提交的時(shí)候,Action中的insert()方法就會(huì)被執(zhí)行,可以通過(guò)改隱藏域中的值的方式來(lái)改變Action要執(zhí)行的方法
2、 解決ActionForm過(guò)多的問(wèn)題
通過(guò)動(dòng)態(tài)ActionForm的方式,即DynaActionForm
步驟
① 在Struts-config.xml
<form-beans>
<form-bean name=”abcForm” type=”org.apache.struts.action.DynaActionForm”>
<form-property name=”userid” type=”java.long.String”></form-property>
</form-bean>
</form-beans>
② 在Struts-config.xml
更改相應(yīng)的action中的attribute和name為abcForm
這樣就配置好了一個(gè)動(dòng)態(tài)的ActionForm
3、 解決動(dòng)態(tài)ActionForm的驗(yàn)證問(wèn)題
通過(guò)動(dòng)態(tài)驗(yàn)證ActonForm的方式,即DynaValidatorForm
步驟
① 在Struts-config.xml
同2的第一步,但是type需要改成org.apache.struts.action.DynaValidatorForm
② 配置一個(gè)validation.xml文件
<form-validation>
<formset>
<form name="abcForm">
<field property="userid" depends="required">
<arg key="err.userid" resource="true"/>
</field>
</form>
</formset>
</form-validation>
③ 在Struts資源文件中配置err.userid、以及errors.required
④ 在Struts-config.xml配置相應(yīng)的action,添加validate=”true”添加驗(yàn)證支持
⑤ 添加struts Plugin插件
設(shè)置plugin class為org.apache.struts.validator.ValidatorPlugIn
添加propertys
Propertyà pathnames
Valueà /WEB-INF/validator-rules.xml,/WEB-INF/validation.xml
這樣一個(gè)驗(yàn)證框架就配置好了!