2005年3月23日
Ubuntu is not an official supported linux version from Oracle, so I still get some errors during the install process even with required configuration, anyway, it can work and what i'm doing here is try to setup an experiment environment, it's enough to me, any one who want to deploy Oracle in product mode should have supported linux platform like RedHat, OK, following is the steps i have to install it:
1. If you were in multihomed enviroment, set the ORACLE_HOSTNAME variable:
export ORACLE_HOSTNAME=machine_name.domain_name
2. Create create OSDBA (dba) group, Oracle Inventory group (oinstall) and a user "oracle" which has "dba" as its login group and oinstall as its 2nd group.
3. Modify /etc/sysctl.conf, set kernel parameter:
kernel.shmall = 2097152
kernel.shmmax = 2147483648
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
fs.file-max = 65536
net.ipv4.ip_local_port_range = 1024 65000
net.core.rmem_default = 1048576
net.core.rmem_max = 1048576
net.core.wmem_default = 262144
net.core.wmem_max = 262144

4. Modify /etc/security/limits.conf to improve the "number of process" and "number of open file" performance for oracle:
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536

5. Modify /etc/pam.d/login, add:
session required /lib/security/pam_limits.so
session required pam_limits.so

6. Modify /etc/profile:
if [ $USER = "oracle" ]; then
if [ $SHELL = "/bin/ksh" ]; then
ulimit -p 16384
ulimit -n 65536
else
ulimit -u 16384 -n 65536
fi
fi

7. Change user to oracle if you haven't done it yet
8. Create base directory, for me it's "/app/oracle"
9. Export ORACLE_BASE, ORACLE_SID
export ORACLE_BASE=/app/oracle
export ORACLE_SID=orcl
10. If you're trying to install oracle with a X window:
DISPLAY=your.ip.address:0.0 ; export DISPLAY
11. run installer:
./runInstaller
12. Oracle should start, if the installer GUI cannot be start, check the error messages, most time it's because a wrong X window configuration, if you are running X window with Xming, just like me, please do make sure to check the "No Access Control" check box in the launch, otherwise, Xming will reject the connection.
13. Now the GUI shoudl open, like what you did in the Windows system, fullfill required value and click next, ingore all errors if there is any condition that is not match, click finish in the last step, it should start install process.
14. After install oracle, the installer GUI will ask you to run two .sh files, run it with a root role.
15. You can try to visit
https://you.ip.address:1158/em to see is that OK for you.
16. How to start oracle:
export ORACLE_BASE=/app/oracle
export ORACLE_HOME=/app/oracle/product/11.2.0/dbhome_1
export ORACLE_OWNR=oracle
export ORACLE_SID=orcl
export PATH=$PATH:$ORACLE_HOME/bin


lsnrctl start

sqlplus /nolog
connect /as sysdba
startup
quit

emctl start dbconsole
Reference
http://download.oracle.com/docs/cd/B19306_01/install.102/b15660/pre_install.htm#BABDFJAE
1. Type command: lsusb
Bus 002 Device 003: ID 19d2:fff5 ONDA Communication S.p.A.
2. Install "usb-modeswitch", then re-plugin modem again and input command "lsusb" again, you should get the following output
Bus 002 Device 003: ID 19d2:fff1 ONDA Communication S.p.A.
3. Notice in step #2, the product code has been changed from "fff5" to "fff1".
4. Install package "wvdial" which is used to dail up
5. Type command: "sudo modprobe usbserial vendor=0x19d2 product=0xfff1", don't forget the "sudo"
6. Type command: "sudo wvdialconf", again don't forget the "sudo", this will detect your modem
7. Modify file "/etc/wvdial.conf", following is what I have:
[Dialer Defaults]
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Modem Type = Analog Modem
ISDN = 0
New PPPD = 1
Phone = #777
Modem = /dev/ttyUSB0
Username = yourName
Password = yourPassword
Baud = 921600
Stupid Mode = 1
Tonline = 0
8. Repeat step #5 again and then if you with not bad luck type in command "sudo wvdial", you should connect in.
9. If bad luck with you, click right-upper corner, there is a connection configuration menu, you can create "Mobile Broadband" connection yourself here, don't forget input the phone number "#777" (for China Telcom) and your username password, after that click connect, this works for me.
10. Good luck with you.
11. BTW, if it still cannot work, try to re-plug in the modem.
1. It will not get data from DB when just open the cursor, data will be loaded as an ongoing basis.
2. SCN: System Change Number/System Commit Number
3. FLASH BACK AS OF SCN;
4. You can also flash back table: FLASHBACK TABLE SOME_TABLE TO SCN :SCN_NUM;
5. But before you do a flash back operation on a table, do make sure you have already enbale ROW MOVEMENT on that table.
1. Do use oracle "Bind variable", it can increase the speed by 90 percent in 10g release1.
2. Understand how to use "lock", read never block write, vice verse.
3. There is a side effect from oracle regarding to the "lock", if you do want to control the access to one row at a specify time (like doing an if 'this row belong to some search condition' then 'modify this row' action), you have to write some logic yourself, for example use the "for update" statement, like: "select * from x where x.id = 1 for update", so that you can lock the row only with id equals to '1' and then modify this row, so that some orther concurrence requests should execute the same sql first, yes, with the same 'for update' statement, and because you already have locked this row(id = 1), orther requests cannot get the access to it, and you get the access control to this row.
4. Regardint to item 3, it will not decrease the concurrence level, because first you only lock the item with id equals to 1 and there maybe thousands of items in your table, second, it will not block the read request.
這該死的問題讓我竟然沒有想到解決方案...腦子生銹了?呵呵,算了...
該問題最經典的解答,簡直是一句話驚醒夢中人啊
“用兩個指針,一個的步長為 1,另外一個的為 2,從表頭開始一起往前走,如果相遇,表明有環路,否則就是沒有了。”
下來,不用說什么了吧,用JAVA實現的話,聲明兩個Iterator A 和 B,A 每次調用兩個NEXT,B只調用一次,如果他們能夠相遇,就是有環...我操
The first is about identity generator, this is something I ingored and find really interesting later when I read back the document.
When you choose "native" (for plain
hibernate) or "AUTO" (for JPA which use
hibernate as provider) as identity generator, it (actually they are the same identity generator but with different name in different scope) will pick other identity generators like identity, sequence, or hilo, depending on the capabilities of the underlying database. Use this generator to keep your mapping metadata portable to different database management systems.
If your underlying DB is oracle, it will automatically create a sequence for you which means choose the sequence as identity generator, that's really interesting, at least for me for the first time when it comes to me.
The second is about the flush and close session operations when to use hibernate with JTA transaction.
You should manually flush your operation by call flush method and close your session by calling close method when you try to use JTA transaction instead of
hibernate Transaction API, these is because
hibernate Transaction API does thoes operations automatically for you. But, with following configuration, it can also be done automatically for you by
hibernate, though you are still with JTA transaction.
hibernate.transaction.flush_before_completion=true
hibernate.transaction.auto_close_session=true
The third is about an interesting code snatch listed as follow:
1 Session session = sessionFactory.openSession();
2 session.beginTransaction();
3 session.save(new Item());
4 session.close();
What happen if you don't commit the transaction? It's depends on the underlying DB, for oracle it will commit any uncommited transactions, but for many other DB vendors, they will roll back any pending transactions.
Timer service in EJB3 with anotation is fairly simple, I give you an example as follow, and it's really simple and self-explanation:
1 package com.ramon.expejb3.session.impl;
2
3 import javax.annotation.Resource;
4 import javax.ejb.Stateless;
5 import javax.ejb.Timeout;
6 import javax.ejb.Timer;
7 import javax.ejb.TimerService;
8
9 import com.ramon.expejb3.session.Greeting;
10
11 @Stateless(name = "Greeting")
12 public class GreetingBean implements Greeting {
13
14 @Resource
15 TimerService ts;
16
17 /* (non-Javadoc)
18 * @see com.ramon.expejb3.session.Greeting#greeting(java.lang.String)
19 */
20 public void greeting(String name) {
21 System.out.println("Hello " + name + ".");
22 ts.createTimer(1 * 1000, 5 * 1000, name);
23 System.out.println("Create timer for " + name + ".");
24 }
25
26 @Timeout
27 public void timeout(Timer timer) {
28 String name = (String)timer.getInfo();
29 System.out.println(name + " TIME OUT.");
30 //timer.cancel();
31 }
32 }
33
It's the "
GreetingBean" I introduced in part one of this series article with TimerService injected,
@Resource anotation inject the time service we want, it's totally free which is supported by the J2EE container that means we do not need any further steps to get the powerful schedule service. In the line 22, I crate a new timer, I think this could be more fit if it was called Task instead, there are several "createTimer" methods with different parameters, the one I used here describe the task should be execute 1 second delay and every 5 second one time in the future, the third parameter can be anything you want to pass in to the task, it can be get back use method Timer.getInfo() like line 28 does here.
Another important anotation here is the @Timeout anotation, this anotation tell container which method will be called when timeout for this task to be executed, you can only specify one timeout method for each Bean, if there is no @Timeout anotation at all, you will get some exception like "No timeout method specified" in Jboss server. Something funny here is that you should mark the timeout method as "public", otherwise, you will get the same error as no timeout method does, I do NOT think it's necessary, because the time out method should only be called by the container, "private" signature is enought for that, with "private" signature container still has the right to access this method with java reflection, nevertheless timer service in EJB3 is still a good tools for use.
I summarize what good/bad for timer service in EJB3 as follow:
Good news:
- It's free, it's supported by the EJB container.
- It's portable, it's supported by the EJB container as specified in EJB3 specification.
- It's easy to use, no need to learn more.
Bad news:
- The feature of EJB3 timer sevice is not as powerful as some third party timer service such as Quartz, but it's enough with EJB3 for ordinary daily job.
- There is no UI for you to monitor the timer you created.
摘要: MDB is the MVP(most valuable player) both in previous EJB version
and EJB3. Although coding with MDB is simple in EJB2.x, EJB3 make it
much more friendly to you. Let's get to the ...
閱讀全文
Recently I did some research on EJB3 programming, find that it's really simple than programming with previous EJB version. Coding in EJB2.X or previous version is really a nightmare for most developers, maybe for this, EJB3 gives me much more impression than Spring when it first comes to me, this article is the first one of these series articles which record the new knowledge I find interesting in EJB3.
Well, let's begin.
EJB3 is simple with AOP and DI, there is no Home interface any more, only with Service Interface and your Service implementation you can create an typical EJB3 application. I will create a simple hello world program in this article, the service interface as follow:
1 package com.ramon.expejb3.session;
2
3 import javax.ejb.Remote;
4
5 @Remote
6 public interface Greeting {
7
8 /**
9 * say hello test
10 * @param name
11 */
12 void greeting(String name);
13
14 }
It's really simple, especially for you that are familiar with programing with Interface, after that is the service implementation code:
1 package com.ramon.expejb3.session.impl;
2
3 import javax.annotation.PostConstruct;
4 import javax.annotation.PreDestroy;
5 import javax.ejb.Stateless;
6
7 import com.ramon.expejb3.session.Greeting;
8
9 @Stateless(name = "Greeting")
10 public class GreetingBean implements Greeting {
11
12 @PostConstruct
13 public void init() {
14 System.out.println("Init Greeting Bean.");
15 }
16
17 @PreDestroy
18 public void destroy() {
19 System.out.println("Garbage collect Greeting Bean.");
20 }
21
22 /* (non-Javadoc)
23 * @see com.ramon.expejb3.session.Greeting#greeting(java.lang.String)
24 */
25 public void greeting(String name) {
26 System.out.println("Hello " + name + ".");
27 }
28 }
29
Still simple and very self-explanation,
@Stateless(name = "Greeting") specify the JNDI name for client invocation. OK, that's all for our EJB jar file, no more file needed for this simple hello application. Execute your ANT script make a jar for it, part of ANT script may look like:
1 <target name="prepareexpejb3" description="Create exp_jsf distribution.">
2 <mkdir dir="${dist.dir}" />
3 <mkdir dir="${build.dir}" />
4 <mkdir dir="${build.core.dir}"/>
5 </target>
6
7 <!-- =================================
8 target: Compile expejb3 classes
9 ================================= -->
10 <target name="compileexpejb3" depends="cleanDist,prepareexpejb3">
11 <javac destdir="${build.core.dir}" debug="yes" deprecation="on" srcdir="${src.dir}">
12 <include name="${core.src.dir}/**" />
13 <classpath refid="expejb3.classpath" />
14 </javac>
15
16 </target>
17
18 <!-- =================================
19 target: Create EJB3 jar
20 ================================= -->
21 <target name="createEJB3Jar" depends="compileexpejb3">
22 <jar jarfile="${dist.dir}/${expejb3.core.name}.jar">
23 <fileset dir="${build.core.dir}"></fileset>
24 </jar>
25 </target>
Put the EJB jar into jboss server server\default\deploy, you should see some log from jboss console like:
1 10:59:27,036 INFO [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.stateless.St
2 atelessContainer
3 10:59:27,051 INFO [JmxKernelAbstraction] installing MBean: jboss.j2ee:jar=expejb3core.jar,name=Gree
4 ting,service=EJB3 with dependencies:
5 10:59:27,208 INFO [EJBContainer] STARTED EJB: com.ramon.expejb3.session.impl.GreetingBean ejbName:
6 Greeting
Which mean that you have successfully deploy your EJB into jboss server, create a client code to invoke your EJB service:
1 package com.ramon.expejb3.session;
2
3 import java.util.Properties;
4
5 import javax.naming.Context;
6 import javax.naming.InitialContext;
7
8 import junit.framework.TestCase;
9
10 public class ExpEJB3BaseTestCase extends TestCase {
11
12 private Properties properties = null;
13
14 private Context context;
15
16 protected void setUp() throws Exception {
17 super.setUp();
18 properties = new Properties();
19 properties.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
20 properties.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
21 properties.put("java.naming.provider.url", "localhost:1099");
22 context = new InitialContext(properties);
23 }
24
25 protected void tearDown() throws Exception {
26 super.tearDown();
27 context = null;
28 properties = null;
29 }
30
31 public final Context getContext() {
32 return context;
33 }
34
35 public final void setContext(Context context) {
36 this.context = context;
37 }
38
39 }
40
1 package com.ramon.expejb3.session.impl;
2
3 import javax.naming.NamingException;
4
5 import com.ramon.expejb3.session.ExpEJB3BaseTestCase;
6 import com.ramon.expejb3.session.Greeting;
7
8 public class GreetingBeanTest extends ExpEJB3BaseTestCase {
9
10 public void testGreeting() {
11 try {
12 Greeting greetService = (Greeting)this.getContext().lookup("Greeting/remote");
13 greetService.greeting("Ramon");
14 } catch (NamingException e) {
15 // TODO Auto-generated catch block
16 e.printStackTrace();
17 }
18 }
19
20 }
21
That's really simple, right? What you should note is that you must include following jars into your classpath when you run this clien test case, otherwise you will get the annoying classNotFound Exception:
1 concurrent.jar
2 jboss-aop-jdk50.jar
3 jboss-aspect-library-jdk50.jar
4 jboss-common.jar
5 jboss-ejb3.jar
6 jboss-ejb3-client.jar
7 jboss-remoting.jar
8 jbossx-client.jar
9 jboss-transaction-client.jar
10 jnp-client.jar
摘要: 本文介紹了編碼字符集的概念以及Java與編碼字符集之間的關系,文章的內容來自于本人工作過程中的經驗積累以及網絡中的相關文章介紹,如果文章中有任何紕漏歡迎讀者指正,讓我們共同討論學習J1.????? 字符字符是抽象的最小文本單位。它沒有固定的形狀(可能是一個字形),而且沒有值。“A”是一個字符,“€”(德國、法國和許多其他歐洲國家通用貨幣的標志)也是一個字符。“中”“國”這是兩個漢字字符。字符僅僅代...
閱讀全文
首先感謝南老師!
??????在計算機里的有符號數,最高位的1用來表示負號,所以,用 0000 0001表示正1,1000 0001表示-1,確實對人來說很直觀。但其實,計算機里的數是用“補碼”表示的。其中正數的補碼就是原來的數(稱為原碼),而負數的補碼是這么算的,我用倒推的來說:
??????補碼 = 反碼 + 1
??????反碼 = 原碼按位取反(1變0,0變1)
??????所以,-1就是1取補碼,過程如下:
??????先取反 0000 0001 ---> 1111 1110?
??????然后加1得補碼: 1111 1110 + 1 = 1111 1111?
????(當然這里為了方便,就取了8位,其實整數現在都是32位了,結果是32個1)。
?????現在,你知道如何計算-2了嗎? 為什么要搞反碼,補碼這么個轉換呢? 這個原因要說長就很長的,但簡單地講,這又是一個在人的直觀和機器的高效之間取一個平衡:
?????我們先來看一個10進制的數運算:
?????1 + (-1) = 0 //10進制中,1加負1應為0.
?????然后,假如用1000 0001來表示-1的話。按照計算機計算加法的規則,它是每位加的,結果是:
?????0000 0001 + 1000 0001 = 1000 0010??//-2
?????結果變成-2了,其中后面兩個0001 相加變成2,而前面的用于表示負號的1,被“繼承”下來了……顯然,原來計算機最直觀的(對人來說也很直觀的)算法,不靈了!怎么辦?痛苦
??? 但更痛苦的事還在0這個數上。按10進制,0和-0可是完全相等的。但如果用二進制,0000 0000 和 1000 0000 參加起運算,可是完全不同。或許可以通過電路設計,來強制讓計算機去實現一個規則: 碰到1000 0000就先轉換為0000 0000。但可要知道加減法計算是計算機計算一切的基礎,如果從這最底層就必須有一個轉換會極大影響性能!何況前面那個問題也必須有個強制規則!規則最好越簡單越好,那就是規定前面的補碼轉換規則,這個轉換過程對于計算機來說很迅速的邏輯電路轉換。
??? 你看,第一個問題 1 + (-1)
? ? 0000 0001 + 1111 1111 = 0000 0000?
????看明白這個計算過程嗎?其實就是最低位的兩個1相加后,造成每一位都進位,最高位直接溢出(丟了)。如果你還算不清,就算算這個10進制的:
????1 + 999 =??1000 (最高位1丟失,就成0了)
????然后是第二個問題,0的表示。如果您把0當成正數,那么它是這樣表示的:
????0000 0000
????如果你當它是負數,那么
????取反 1111 1111 ,再加1,以求補 ,哈哈又成 0000 0000這回在邏輯上沒有錯誤了!明白了吧?當補我在學習這一段知識時,只能說:高,實在高! 想出補碼的前輩,真是高人啊。
This article is focused on which approach we should choose for unit testing against Struts action, I hope it will give you some help when you have question on how to do unit testing against the controller in MVC.
OK, let's begin!
In container? Mock objects?
There are two kinds of testing, one is in-container and the other is do testing with mock objects. Generally speaking, it was considered to be more really and truly unit testing when you do testing with mock objects, especially when you do testing against java source files which should be run in J2EE container, but as our code become complex which contain more layers, the controller(Struts) will have more depends on the other layer which may be EJB service or other business objects, so when you do unit testing against view layer(here is Struts), it will be a huge work for you to construct the mock objects and also it will have more source code changed as you apply mock objects in your source code, the following is a simply description which describe the classic three layers project, and also considerd to be the most common type of web based project.
e.g. the Struts action class first call the EJB factory to get an EJB service, and then ask this EJB service to do the work according to the business logic and return the value we need, with the value EJB service returned the action class can choose which page to redirect or do some other data processing ,this could be the classic three layers type, maybe the most common type project we used in our project.
Therefore, it may not be the best choice for every web based project to apply mock objects unit testing. In the case that Struts action class is close tied with your business object, in-container testing may be an alternate choice for you, because it save your time to write mock objects and the workload to apply the mock objects into your source files but supply the same testing resluts.
In-container testing sounds good, but when you do testing in this style, it first assume that the depended business service classes used in our Struts action must be verified, if the depended service classes have some defect that happen to be met when we run in-container testing, it will take more time to find which cause the error indeed.
But I think if we have a complete testing procedure, which cover the service layer and the controller, the service layer have already been verified properly, in-container testing is really the best choice for you to use for testing action class. For project in practice, the Struts action is more or less close tied with other layer, it's not realistic to spend more time on writing mock objects or modifying your source code to apply the mock objects. In my opinion, the recommended solution is that you should focus on Struts layer testing, if the Struts action code is close tied with other service layer which I mean is that there may be only one execute() method in every Struts action take charge for the whole business logic, you should use in-container testing, let other unit testing stuff take charge for service layer which may be out of container unit testing against EJB, in this way you can write your test case at your pleasure, forget the depended layers for a while, the container will take care for other layers for you, and also it will save you lots of time for writing mock objects, the container will give you the real objects instead of mock objects.Mock object testing is more often used for the simple Struts action or the case that it could be influenced by the container when you do unit testing against Struts action.
I will write some thing?when I have time tomorrow, sorry, it's already 1:00 AM at midnight, so you guys?could see some thing right now, hey hey. It's mainly about how to automatic do unit testing in container with strutstestcase and ANT, hope it will be useful for you guys.
由于最近在把以前的一個設計移到hibernate上來,所以需要用到one-to-one,因為在以前的設計中需要用到在一個主表中對于多個子表的主鍵關聯,所以一開始就想到了one-to-one的應用,覺得這樣解決不但不會引起以前數據設計的改變,也能夠很好的利用hibernate所帶來的OR優勢,可是當實際使用的時候發現,在插入數據的時候可以有選擇的在任意子表中進行插入,所有的結果都在原來的預期之中,但是在查詢的時候,比如說只查詢主表中的內容
From tableMain僅僅執行看起來十分簡單的一條語句,你所期望的是他緊緊查詢T_MAIN這張主表,可是結果確實hibernate通過多個外連接將所有的子表一口氣的全部查詢出來
select * from t_main main outer join t_sub1 sub1 on main.id = sub1.id outer join t_sub2 sub2 on main.id = sub2.id... 如此的效率絕對讓你頭痛不已,不僅如此,如果你通過首先獲得子表t_sub1的某個主鍵ID,然后通過這個主鍵查詢出子表對象,在關聯至住表,同樣的情況又會發生,又會生成類似的SQL語句,這樣一來看來對于這個設計應用one-to-one本身就是一種錯誤,是這樣嗎?
或許有人認為我們在每個one-to-one中加入lazy="true"這個屬性會杜絕上述情況的發生,經過筆者的證實即便你加入了lazy="true",也不會帶來任何的改變;又或者在hibernate.config中加入fetch depth屬性以及在每個關聯中設置outer-join="false",這些都不會引起本質上的變化,加入outer-join="false"其實結果只是將原有的outer join語句改變成多條sql語句而已,并沒發生什么本質變化,反而效率更低了。
該怎么辦呢?我們先仔細研究一下one-to-one的概念,one to one代表一對一,在一般的模型中很少會遇到one-to-one這種概念,因為他十分強調一對一的概念,就好比一個人他只有一個身體和一個頭而已,頭和身體是十分好的例子,因為有身體必定只有一個頭,而且說到了身體必定要說頭,就好像看了某個女孩的身材必定想知道她的長相如何(-_-),所以在這時我們使用one-to-one,因為這種一對一的關系是很強的,而且從對象中取得body必定會取得他所關聯的head,這樣的情況下使用outer-join是十分方便和有效率的,因為它使用了outer join查詢從而避免了兩條到數據庫的查詢語句,而且在這種情況下也只需要在body_hbm.xml中設置一個one-to-one即可,所以在這種確實是一對一
而且在主表中一對一的關聯個數(即主表中one-to-one標簽)十分少的情況下,使用one-to-one是一種很不錯的解決辦法。
如果一個主表會對多個子表都進行one-to-one關聯呢,就像我們一開始遇到的這種情況,比如你不僅僅只想了解那個你中意的女孩的身材和臉蛋,而且還想知道他的學歷,身世等等一切,在這種情況下,如果我們都是用多個one-to-one在主表中的話,那情況正如我們一開始看見的,是十分可怕的,該怎么做呢?不妨考慮一下使用one-to-many,什么,many?一開始聽到many這個詞的時候,我也覺得挺驚訝的這明明是多個一對一的關聯為什么要用到many呢?其實many并沒有一定要說是大于一的,你就只在它的many中存在一個關聯它有能乃你何呢?如果用到many的話,我們就需要改動數據表的設計了,在每個有關連的子表中加入一列main_id代表主表中該記錄的主鍵子段值,只需要這樣子改動就可以了,這樣所帶來的效果絕對是值得你這樣做的,然后我們就按照以往的one-to-many來設計就好了
在body.hbm.xml加入(一到head的關聯舉例,其他的關聯按照這樣的格式添加即可)
<set name="head" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="ID0000"/>
<one-to-many class="com.xx.Head"/>
</set>
在head.hbm.xml加入
<many-to-one name="body" column="ID0000" class="com.xx.Body" not-null="true"/>
行了,經過上面的改動我們就擺脫了查詢時多個outer-join的困擾,只在需要的時候才對子表進行查詢,因為設置了lazy="true",所以一切的一切都在我們的預料之中,我們如果希望獲得body的話hibernate絕對不會把它的head 也查詢出來,節省了查詢是所需要的負擔,除非到了我們十分需要head的情況才會進行關聯查詢,獲得所需要的head結果。
所以由此看來
在one-to-one這種一對一的關系不是很強的情況下,或者是在一張表中存在多個one-to-one的情況下,使用one-to-many來代替one-to-one不失為一種不錯的做法,當然更重要的良好的數據庫設計,hibernate畢竟只是末,
千萬不要本末倒置。
one-to-one在hibernate中可以用來作為兩張表之間的主鍵關聯,這也是hibernate中主鍵關聯的一種用法,這樣在一張表中的ID,在生成另外一張表的同時回自動插入到相應的ID字段中去,相應的XML文件設置比較簡單,舉例如下:
<!-- 建立一對一的到Address的映射,這個是寫在User的XML配置文件中的 -->
<!-- 相應的User bean(PO)中也要添加屬性 com.xx.Address address-->
<one-to-one name="address" cascade="all" class="com.xx.Address"/>
<!-- cascade的屬性設置不再重復了,可以查看hibernate文檔 -->
<!-- 建立一對一的到User的映射,這個是寫在Address的XML配置文件中的 -->
<!-- 相應的Address bean(PO)中也要添加屬性 com.xx.User user--> -->
<one-to-one name="user" class="com.xx.User" constrained="true"/>
為了在Address中使用User中的主鍵ID值,我們需要設置Address中的主鍵生成規則,如下所示,采用foreign關鍵字
<id column="ID" name="id" type="long" unsaved-value="0">
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
這里需要注意的是property的屬性值必須與上面到User的映射所填寫的name屬性值一致,這樣就完成了one-to-one的映射關系。
上面的過程都很簡單,下面我來說說這里需要注意的地方:
1. 在設置屬性ID的時候必須注意字段的長度,如筆者這樣使用oracle的sequence來生成ID,其長度有14位之長,則應選擇hibernate類型long,對應的實體中應選擇Long,這樣不會出現溢出的情況。
2. 在測試的時候必須要注意這兩張表之間因為已經存在了一對一的關系,所以我們不能只寫
user.setAddress(address);
而忽略了
address.setUser(user);
這樣在做插入的時候會報出attempted to assign id from null one-to-one property: address的錯誤,這一點初學者會經常犯,筆者也是其中之一。
3. 如果不寫cascade="all"或者寫成cascade="none"的話,即使你寫了
user.setAddress(address);
address.setUser(user);
也不會發生任何事情,只有user會被存儲。
以上是一些筆者經歷的小經驗,如果有不對的地方歡迎指正。
在很多情況下,我們使用Hibernate在已經建立好數據庫的基礎上。在oracle中,如果已經建立好的數據庫中使用了sequence,則可以按照下面的步驟把它引入到Hibernate中:
1、在oracle 首先創建sequence
create sequence seq_id
minvalue 1
start with 1
increment by 1
cache 20;
2.在你的hbm.xml中的配置
<id column="ID0000" name="id" type="integer">
<generator class="sequence">
<param name="sequence">seq_id</param>
</generator>
</id>
這樣再插入數據的時候,Hibernate回自動生成如下語句:
hibernate: select seq_id.nextval from dual
hibernate: insert into YXJK.T_YXJK_WHRYTXL (XM0000, ZW0000, LXDH00, SJHM00, DZYJ00,
IP0000, ID0000) values (?, ?, ?, ?, ?, ?, ?)
自動生成下一個序列值,然后將對象插入表中。
在使用的時候需要注意,Hibernate對于sequence的主鍵的要求是一定要是shor,long,或者integer