JavaMuse

          2007年3月13日 #

          Unit-testing Hibernate with HsqlDB

          The Motivation

          I've used lots of methods to transform data between databases and object code. From hand-coded SQL to JDO to EJB. I've never found a method I liked particularly well. This distaste has become especially acute since adopting test-driven development (TDD) as a guiding philosophy.

          Unit-testing should have as few barriers as possible. For relational databases those barriers range from external dependencies (is the database running?) to speed to keeping the relational schema synchronized with your object model. For these reasons it is vital to keep database access code away from the core object model and to test as much as possible without touching a real database.

          This has often led me to one of two patterns. The first is externalizing all data access to domain objects and their relationships to separate classes or interfaces. These are typically data store objects that can retrieve, edit, delete and add domain entities. This is the easiest to mock-out for unit-testing, but tends to leave your domain model objects as data-only objects with little or no related behavior. Ideally access to child records would be directly from the parent object rather than handing the parent object to some third-party class to determine the children.

          The other method has been to have the domain objects have access to an interface into the data-mapping layer a la Martin Fowler’s Data Mapper pattern. This has the advantage of pushing object relationships inside the domain model where the object-relational interface can be expressed once. Classes that use the domain model are unaware of the persistence mechanism because it is internalized into the domain model itself. This keeps your code focused on the business problem you are trying to solve and less about the object-relational mapping mechanism.

          My current project involves crunching a number of baseball statistics and running simulations with the data. Since the data was already in a relational database it was a chance for me to explore the Hibernate object-relational mapping system. I have been very impressed with Hibernate, but I ran into the problem was trying to insert a layer of indirection while using Hibernate as my data mapper for unit-testing. The extra layer was so flimsy that it felt embarrassing to write it. The real deployed version was simply a pass-through to a Hibernate-specific implementation. Even worse, the mock versions had more complexity in them than the real "production" version simply because they didn't have some of the basic object storage and mapping that came with Hibernate.

          I also had enough complex Hibernate query usage that I wanted to unit-test this significat portion of the application. However, testing against a ‘live’ database is a bad idea, because it almost invariably introduces a maintenance nightmare. In addition, since tests are best when they are independent from each other, using the same obvious primary keys in test fixture data means you have to create code to clean the database before each test case, which is a real problem when lots of relationships are involved

          By using HSQLDB and Hibernate's powerful schema-generation tool I was able to unit-test the mapping layer of the application and find numerous bugs in my object queries I would not have found as easily by manual testing. With the techniques outlines below I was able unit-test my entire application during development with no compromises in test coverage.

          Setting up HSQLDB

          I used version 1.7.3.0 of HSQLDB. To use an in-memory version of the database you need to invoke the static loader for the org.hsqldb.jdbcDriver. Then when you get a JDBC connection you use JDBC url such as jdbc:hsqldb:mem:yourdb where 'yourdb' is the name of the in-memory database you want to use.

          Since I'm using Hibernate (3.0 beta 4), I hardly ever need to touch real-live JDBC objects. Instead I can let Hibernate do the heavy lifting for me--including automatically creating the database schema from my Hibernate mapping files. Since Hibernate creates its own connection pool it will automatically load the HSQLDB JDBC driver based on the configuration code lives in a class called TestSchema. Below is the static initializer for the class.

          ?1?public?class?TestSchema?{
          ?2?
          ?3?????static?{
          ?4?????????Configuration?config?=?new?Configuration().
          ?5?????????????setProperty("hibernate.dialect",?"org.hibernate.dialect.HSQLDialect").
          ?6?????????????setProperty("hibernate.connection.driver_class",?"org.hsqldb.jdbcDriver").
          ?7?????????????setProperty("hibernate.connection.url",?"jdbc:hsqldb:mem:baseball").
          ?8?????????????setProperty("hibernate.connection.username",?"sa").
          ?9?????????????setProperty("hibernate.connection.password",?"").
          10?????????????setProperty("hibernate.connection.pool_size",?"1").
          11?????????????setProperty("hibernate.connection.autocommit",?"true").
          12?????????????setProperty("hibernate.cache.provider_class",?"org.hibernate.cache.HashtableCacheProvider").
          13?????????????setProperty("hibernate.hbm2ddl.auto",?"create-drop").
          14?????????????setProperty("hibernate.show_sql",?"true").
          15?????????????addClass(Player.class).
          16?????????????addClass(BattingStint.class).
          17?????????????addClass(FieldingStint.class).
          18?????????????addClass(PitchingStint.class);
          19?
          20?????????HibernateUtil.setSessionFactory(config.buildSessionFactory());
          21?????}
          22?

          Hibernate provides a number of different ways to configure the framework, including programmatic configuration. The code above sets up the connection pool. Note that the user name 'sa' is required to use HSQLDB's in-memory database. Also be sure to specify a blank as the password. To enable Hibernate's automatic schema generation set the hibernate.hbm2ddl.auto property to 'create-drop'.

          Testing In Practice

          My project is crunching a bunch of baseball statistics so I add the four classes that I'm mapping ( Player, PitchingStint, BattingStint and FieldingStint). Finally I create a Hibernate SessionFactory and insert it into the HibernateUtil class which simply provides a single access method for my entire application for Hibernate sessions. The code for the HibernateUtil is below:

          ?1?import?org.hibernate.*;
          ?2?import?org.hibernate.cfg.Configuration;
          ?3?
          ?4?public?class?HibernateUtil?{
          ?5?
          ?6?????private?static?SessionFactory?factory;
          ?7?
          ?8?????public?static?synchronized?Session?getSession()?{
          ?9?????????if?(factory?==?null)?{
          10?????????????factory?=?new?Configuration().configure().buildSessionFactory();
          11?????????}
          12?????????return?factory.openSession();
          13?????}
          14?
          15?????public?static?void?setSessionFactory(SessionFactory?factory)?{
          16?????????HibernateUtil.factory?=?factory;
          17?????}
          18?}
          19?

          Since all of my code (production code as well as unit-tests) get their Hibernate sessions from the HibernateUtil I can configure it in one place. For unit-tests the first bit of code to access the TestSchema class will invoke the static initializer which will setup Hibernate and inject the test SessionFactory into the HibernateUtil. For production code the SessionFactory will be initialized lazily using the standard hibernate.cfg.xml configuration mechanism.

          So what does this look like in the unit-tests? Below is a snippet of a test that checks the the logic for determining what positions a player is eligible to play at for a fantasy baseball league:

          ?1??public?void?testGetEligiblePositions()?throws?Exception?{
          ?2?????????Player?player?=?new?Player("playerId");
          ?3?????????TestSchema.addPlayer(player);
          ?4?
          ?5?????????FieldingStint?stint1?=?new?FieldingStint("playerId",?2004,?"SEA",?Position.CATCHER);
          ?6?????????stint1.setGames(20);
          ?7?????????TestSchema.addFieldingStint(stint1);
          ?8?
          ?9?????????Set<Position>?positions?=?player.getEligiblePositions(2004);
          10?????????assertEquals(1,?positions.size());
          11?????????assertTrue(positions.contains(Position.CATCHER));
          12?????}
          13?

          I first create a new Player instance and add it to the TestSchema via the addPlayer() method. This step must occur first because the FieldingStint class has a foreign-key relationship to the Player class. If I didn't add this instance first I would get a foreign-key constraint violation when I try to add the FieldingStint. Once the test-fixture is in place I can test the getEligiblePositions() method to see that it retrieves the correct data. Below is the code for the addPlayer() method in the TestSchema. You will notice that Hibernate is used instead of bare-metal JDBC code:
          ?1?public?static?void?addPlayer(Player?player)?{
          ?2?????????if?(player.getPlayerId()?==?null)?{
          ?3?????????????throw?new?IllegalArgumentException("No?primary?key?specified");
          ?4?????????}
          ?5?
          ?6?????????Session?session?=?HibernateUtil.getSession();
          ?7?????????Transaction?transaction?=?session.beginTransaction();
          ?8?????????try?{
          ?9?????????????session.save(player,?player.getPlayerId());
          10?????????????transaction.commit();
          11?????????}
          12?????????finally?{
          13?????????????session.close();
          14?????????}
          15?????}
          16?

          One of the most important things in unit-testing is to keep your test-cases isolated. Since this method still involves a database, you need a way to clean your database prior to each test case. I have four tables in my schema so I wrote a reset() method on the TestSchema that removes all rows from the tables using JDBC. Note because HSQLDB knows about foreign keys, the order in which the tables are deleted is important. Here is the code:

          ?1?public?static?void?reset()?throws?SchemaException?{
          ?2?????????Session?session?=?HibernateUtil.getSession();
          ?3?????????try?{
          ?4?????????????Connection?connection?=?session.connection();
          ?5?????????????try?{
          ?6?????????????????Statement?statement?=?connection.createStatement();
          ?7?????????????????try?{
          ?8?????????????????????statement.executeUpdate("delete?from?Batting");
          ?9?????????????????????statement.executeUpdate("delete?from?Fielding");
          10?????????????????????statement.executeUpdate("delete?from?Pitching");
          11?????????????????????statement.executeUpdate("delete?from?Player");
          12?????????????????????connection.commit();
          13?????????????????}
          14?????????????????finally?{
          15?????????????????????statement.close();
          16?????????????????}
          17?????????????}
          18?????????????catch?(HibernateException?e)?{
          19?????????????????connection.rollback();
          20?????????????????throw?new?SchemaException(e);
          21?????????????}
          22?????????????catch?(SQLException?e)?{
          23?????????????????connection.rollback();
          24?????????????????throw?new?SchemaException(e);
          25?????????????}
          26?????????}
          27?????????catch?(SQLException?e)?{
          28?????????????throw?new?SchemaException(e);
          29?????????}
          30?????????finally?{
          31?????????????session.close();
          32?????????}
          33?????}
          34?

          When bulk deletes become finalized in Hibernate 3.0 we should able to remove this last bit of direct JDBC from our application. Until then we have to get a Connection and issue direct SQL to the database.

          Be sure not to close your Connection, closing the Session is sufficient for resource cleanup. Out of habits developed from writing lots of hand-crafted JDBC code, the first version closed the JDBC Connection. Since I configured Hibernate to create a connection pool with only one Connection I completely torpedoed any tests after the first one.Be sure to watch out for this!

          Since you can never be sure what state the database may be in when your test class is running (imagine running all of your test cases), you should include database cleanup in your setUp() methods like so:

          1?public?void?setUp()?throws?Exception?{
          2?????????TestSchema.reset();
          3?????}
          4?

          Conclusion

          Being able to test against a real-live RDBMS without all of the hassles of trying to run tests against your deployed database is essential, even when working with sophisticated O/R mappers like Hibernate. The example I showed here is not exclusive to Hibernate and could probably be made to work with JDO or TopLink, though Hibernate makes this kind of testing particularly easy since it has a built-in schema generation tool. With a setup like the one described above you don't ever have to leave the comfort of your IDE and still have extensive test coverage over your code.

          posted @ 2007-03-13 14:05 滿山紅葉 閱讀(432) | 評(píng)論 (0)編輯 收藏

          HSQLDB文檔

          一 什么是HSQLDB
          HSQLDB具有以下特點(diǎn):
          l ???????? 是一個(gè)開放源代碼的JAVA 數(shù)據(jù)庫(kù)
          l ???????? 具有標(biāo)準(zhǔn)的SQL 語法和JAVA 接口
          l ???????? HSQLDB 可以自由使用和分發(fā)
          l ???????? 非常簡(jiǎn)潔和快速的
          l ???????? 具有內(nèi)存數(shù)據(jù)庫(kù),獨(dú)立數(shù)據(jù)庫(kù)和C/S 數(shù)據(jù)庫(kù)三種方式
          l ???????? 可是在APPLET 中使用
          更多的細(xì)節(jié):
          l ???????? 索引可以被創(chuàng)建和自動(dòng)使用
          l ???????? 支持事務(wù)處理
          l ???????? 允許表關(guān)聯(lián)
          l ???????? 完整性引用和約束
          l ???????? 支持JAVA存儲(chǔ)過程和函數(shù)
          l ???????? 數(shù)據(jù)庫(kù)可以生成SQL腳本
          l ???????? 使用用戶名,密碼,訪問權(quán)限等安全機(jī)制
          l ???????? 可以被JAVA1.1和JAVA2編譯
          建立在HypersonicSQL基礎(chǔ)上的HSQLDB,是一個(gè)通用目的的數(shù)據(jù)庫(kù),非常的小,而且易于安裝和使用。可以用于APPLETS中 ,測(cè)試中,應(yīng)用系統(tǒng)中。
          由于提供了標(biāo)準(zhǔn)SQL和JDBC接口,HSQLDB可以方便的和其他數(shù)據(jù)庫(kù)之間進(jìn)行數(shù)據(jù)轉(zhuǎn)換。
          HSQLDB的當(dāng)前最新版本是1.7.1,以壓縮包的形式提供,包括可以使用的JAR文件,文檔,源代碼,測(cè)試程序,例子等。
          操作模式介紹
          HSQLDB有兩種操作模式:
          l ???????? 進(jìn)程內(nèi)模式(只用在同一個(gè)JVM里的應(yīng)用程序才可以訪問數(shù)據(jù)庫(kù))
          l ???????? C/S模式(多個(gè)計(jì)算機(jī)/系統(tǒng)可以訪問同一個(gè)數(shù)據(jù)庫(kù))
          ?
          進(jìn)程內(nèi)訪問模式
          進(jìn)程內(nèi)訪問模式也就是獨(dú)立模式。這里的獨(dú)立模式是相對(duì)于C/S模式(客戶端程序訪問數(shù)據(jù)庫(kù)服務(wù)器)而言的。這里,數(shù)據(jù)庫(kù)和應(yīng)用程序運(yùn)行在同一個(gè)JVM下。這個(gè)時(shí)候的數(shù)據(jù)庫(kù)實(shí)際上就是相當(dāng)于被應(yīng)用程序調(diào)用的代碼庫(kù)。程序和數(shù)據(jù)庫(kù)通過通用的JDBC調(diào)用進(jìn)行通訊,但是這種調(diào)用是內(nèi)部調(diào)用,不需要通過網(wǎng)絡(luò)通訊。
          在這個(gè)模式下,同一時(shí)間一個(gè)數(shù)據(jù)庫(kù)只能有一個(gè)應(yīng)用程序訪問,否則,就要使用C/S模式(允許多個(gè)JVM或者計(jì)算機(jī)在同一時(shí)間訪問同一個(gè)數(shù)據(jù)庫(kù))。
          ?
          這種模式下的JDBC的URL如下:
          jdbc:hsqldb:test
          這里,test是數(shù)據(jù)庫(kù)文件名。另一個(gè)例子(WINDOWS系統(tǒng)下):
          				jdbc:hsqldb:c:\db\test 
          		
          ?
          ?
          C/S 訪問模式
          這種模式下數(shù)據(jù)庫(kù)和應(yīng)用程序不是運(yùn)行在同一個(gè)JVM進(jìn)程下,而是有自己獨(dú)立的進(jìn)程或者是獨(dú)立的機(jī)器。 不需要客戶端程序進(jìn)入服務(wù)器的文件系統(tǒng)。這種模式下的數(shù)據(jù)庫(kù)操作模式和一些大的數(shù)據(jù)庫(kù)(比如SQL SERVER,ORACLE等)沒什么區(qū)別的。可以在INTERNET或者INTRANET。
          HSQLDB除了有自己的訪問協(xié)議,還支持標(biāo)準(zhǔn)的HTTP協(xié)議,從而可以穿越防火墻或者代理服務(wù)器來訪問數(shù)據(jù)庫(kù)。
          In all Server modes the actual database file name is specified in the Java command that starts the server. This can be the dot "." for all-in-memory operation or the path for the database name
          ?
          服務(wù)器模式一共有三種:SERVER,WEBSERVER和SERVLET。
          ?
          l ???????? SERVER
          這種模式下的通訊協(xié)議是建立在TCP/IP基礎(chǔ)上的HSQL專有協(xié)議。每個(gè)客戶端都有一個(gè)獨(dú)立的連接。這種模式的響應(yīng)速度是非常快的,如果使用C/S模式,應(yīng)該更多的采用這種服務(wù)模式。
          這種模式下的JDBC URL是:
          jdbc:hsqldb:hsql://hsqldbsrv
          這里,hsqldbsrv是機(jī)器名稱。如果一臺(tái)機(jī)器上跑多個(gè)服務(wù)器,需要指定端口,例如:jdbc:hsqldb:hsql://hsqldbsrv:9002,如果是本地計(jì)算機(jī),則使用localhost:jdbc:hsqldb:hsql://localhost。
          ?
          l ???????? WEBSERVER
          有些時(shí)候,由于防火墻或者代理服務(wù)器的存在,需要使用HTTP協(xié)議進(jìn)行通訊,系統(tǒng)提供一個(gè)小而簡(jiǎn)單的WEBSERVER用來相應(yīng)針對(duì)數(shù)據(jù)庫(kù)的查詢,例如:
          				jdbc:hsqldb:http://websrv
          		
          ?
          l ???????? SERVLET
          這種模式和WEBSERVER模式很類似,數(shù)據(jù)庫(kù)運(yùn)行在一個(gè)SERVLET里,而SERVLET可以運(yùn)行在幾乎所有的WEBSERVER里。而且和JAVA SERVLETE API兼容(測(cè)試環(huán)境是J2DK2.1)。這是通過網(wǎng)絡(luò)直接訪問的。如果你的SERVLET不能直接訪問這個(gè)數(shù)據(jù)庫(kù),就不要使用這種模式。
          ?
          全內(nèi)存訪問(All-In-Memory )模式
          所謂全內(nèi)存訪問模式,就是所有的數(shù)據(jù)(包括索引和記錄)都保存在主內(nèi)存里。這意味著數(shù)據(jù)庫(kù)的大小是受到內(nèi)存大小的限制的(不能超過內(nèi)存的大小)。支持這種模式的原因是:
          l ???????? 在非日志模式下,這種模式稍微快些
          l ???????? 可以在APPLET下使用
          l ???????? 用來存儲(chǔ)臨時(shí)數(shù)據(jù)(應(yīng)用系統(tǒng)的數(shù)據(jù)緩存)All-In-Memory
          JDBC URL如下:
          				jdbc:hsqldb:. 
          		
          ?
          內(nèi)存和硬盤結(jié)合訪問模式
          ?
          在這種模式下,數(shù)據(jù)庫(kù)的改變會(huì)寫入到硬盤中,這就意味著在數(shù)據(jù)庫(kù)啟動(dòng)時(shí),內(nèi)存里的表會(huì)根據(jù)他們的數(shù)據(jù)重新創(chuàng)建。或者說,可以創(chuàng)建表來保存數(shù)據(jù),在訪問數(shù)據(jù)庫(kù)時(shí),只有少量記錄時(shí)保存在內(nèi)存里的。可以在創(chuàng)建的時(shí)候使用''''CREATE CACHED TABLE''''來代替''''CREATE TABLE''''。從而支持大表(這些表的記錄相對(duì)于內(nèi)存來說太大了)。被緩存的表的索引也可以保存到硬盤中。因此,數(shù)據(jù)庫(kù)的大小就可以不受到內(nèi)存大小的限制。進(jìn)入緩存表要比從內(nèi)存表里獲取數(shù)據(jù)要慢些。從1.7.0版本開始,支持第三種模式:數(shù)據(jù)可以存儲(chǔ)在文本文件(如CSV格式的文件)中。對(duì)應(yīng)的語句時(shí):''''CREATE TEXT TABLE''''。
          在關(guān)閉數(shù)據(jù)庫(kù)前,當(dāng)前狀態(tài)會(huì)被保存到磁盤中。緩存表中的數(shù)據(jù)會(huì)被保存到一個(gè)單獨(dú)的文件中。啟動(dòng)HSQLDB時(shí),數(shù)據(jù)庫(kù)從磁盤中載入數(shù)據(jù)(SQL腳本被執(zhí)行),如果數(shù)據(jù)庫(kù)被毀壞(比如使用Ctrl+C或者斷電),數(shù)據(jù)也不會(huì)丟失。這是因?yàn)楫?dāng)下次數(shù)據(jù)庫(kù)重新啟動(dòng)時(shí),它使用腳本恢復(fù)到最近一次(有腳本文件的那次)的狀態(tài)。
          ?
          ?
          混合綁定模式
          所有的模式都可以在一個(gè)程序里使用,系統(tǒng)可以在統(tǒng)一時(shí)間使用這四種模式,去連接四種不同的數(shù)據(jù)庫(kù),例如:
          				c1=DriverManager.getConnection("jdbc:hsqldb:.","sa",""); 
          		
          				c2=DriverManager.getConnection("jdbc:hsqldb:test","sa","");
          		
          				c3=DriverManager.getConnection("jdbc:hsqldb:http://dbserver","sa",""); 
          		
          				c4=DriverManager.getConnection("jdbc:hsqldb:hsql://dbserver","sa","");
          		
          在這個(gè)例子中,四個(gè)連接被打開:
          c1是內(nèi)存數(shù)據(jù)庫(kù);c2打開的是本地?cái)?shù)據(jù)庫(kù)test;c3使用http協(xié)議連接dbserver數(shù)據(jù)庫(kù);c4也是連接dbserver機(jī)器,但是使用的是更快的hsql協(xié)議。這里的限制就是:只有一個(gè)進(jìn)程內(nèi)的全內(nèi)存進(jìn)程是可用的。
          ?
          比較
          每種模式或配置都有不同的細(xì)節(jié)和好壞兩個(gè)方面:
          l ???????? 事務(wù)處理
          對(duì)于webserver和servlet模式而言,由于HTTP協(xié)議是無狀態(tài)的,因此,每個(gè)查詢數(shù)據(jù)庫(kù)都建立新的連接。每次查詢都需要發(fā)送用戶名和密碼到數(shù)據(jù)庫(kù)中,然后建立一個(gè)新的連接,同時(shí)也建立一個(gè)新的事務(wù)(因?yàn)槭聞?wù)是綁定到連接中的)。可以使用’cookies’,但是現(xiàn)在還沒有實(shí)現(xiàn)。
          l ???????? 并發(fā)訪問
          SERVER模式允許系統(tǒng)和管理工具(比如DatabaseManager同時(shí)訪問數(shù)據(jù)庫(kù))。
          l ???????? 數(shù)據(jù)庫(kù)性能優(yōu)化因素
          內(nèi)存數(shù)據(jù)庫(kù)不需要訪問系統(tǒng),因此是最快的。其他模式的數(shù)據(jù)庫(kù)需要訪問文件系統(tǒng),每個(gè)INSERT/UPDATE/DELETE操作都要保存到磁盤中,因此速度慢些。如果select和delete查詢命中了緩存表的信息,則速度幾乎和內(nèi)存表速度一樣快,否則就要慢許多(因?yàn)橐筒僮飨到y(tǒng)的文件系統(tǒng)交互)。
          l ???????? 每個(gè)statement的傳輸時(shí)間
          在SERVER模式,每個(gè)statement都需要通過TCP/IP協(xié)議傳送到服務(wù)端,然后將結(jié)果返回到客戶端。而webserver和servlet模式則需要更多的時(shí)間,因?yàn)槊看蝧tatement都需要重新建立連接。相對(duì)照的,進(jìn)程內(nèi)模式則是在一個(gè)系統(tǒng)內(nèi)部傳送數(shù)據(jù),就快多了。
          ?
          l ???????? 以APPLET方式運(yùn)行
          這就是全內(nèi)存操作。

          posted @ 2007-03-13 14:01 滿山紅葉 閱讀(356) | 評(píng)論 (0)編輯 收藏

          2007年2月28日 #

          vimtutor 亂碼

          iconv -f gb2312 /usr/share/vim/vim70/tutor/tutor.zh.euc -t utf-8 > tmp.txt
          mv tmp.txt /usr/share/vim/vim70/tutor/tutor.zh.euc

          posted @ 2007-02-28 19:06 滿山紅葉 閱讀(258) | 評(píng)論 (0)編輯 收藏

          2007年2月17日 #

          ubuntu 6.10 edgy 安裝與配置

          1、設(shè)置網(wǎng)絡(luò),上網(wǎng)安裝和更新:
          sudo pppoeconf
          (打開連接:pon dsl-provider; 關(guān)閉連接:poff dsl-provider)
          2、設(shè)置安裝源apt:
          先備份原有的安裝源文件:sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
          修改安裝源:sudo vim /etc/apt/sources.list 用下面的源全部代替原來的(電信用戶)
          deb http://ubuntu.cn99.com/ubuntu/ edgy main restricted universe multiverse
          deb http://ubuntu.cn99.com/ubuntu/ edgy-security main restricted universe multiverse
          deb http://ubuntu.cn99.com/ubuntu/ edgy-updates main restricted universe multiverse
          deb http://ubuntu.cn99.com/ubuntu/ edgy-proposed main restricted universe multiverse
          deb http://ubuntu.cn99.com/ubuntu/ edgy-backports main restricted universe multiverse
          deb-src http://ubuntu.cn99.com/ubuntu/ edgy main restricted universe multiverse
          deb-src http://ubuntu.cn99.com/ubuntu/ edgy-security main restricted universe multiverse
          deb-src http://ubuntu.cn99.com/ubuntu/ edgy-updates main restricted universe multiverse
          deb-src http://ubuntu.cn99.com/ubuntu/ edgy-proposed main restricted universe multiverse
          deb-src http://ubuntu.cn99.com/ubuntu/ edgy-backports main restricted universe multiverse
          deb http://ubuntu.cn99.com/ubuntu-cn/ edgy main restricted universe multiverse
          3、
          更新源和更新系統(tǒng):
          sudo apt-get update
          sudo apt-get dist-upgrade
          4、
          安裝開發(fā)環(huán)境:
          本人想學(xué)習(xí)一下Linux下的C,C++程序開發(fā),這幾天一直在研究Linux下的C語言編譯環(huán)境的建立,應(yīng)為新裝好的Ubuntu里面無法編譯最簡(jiǎn)單的C語言,所以要配置一番,這幾天也有一點(diǎn)心得,寫下來和大家一起學(xué)習(xí)。
          原來我以為安裝配置非常麻煩,但是在新立得的幫助下很快就能配置好。
          我先安裝了一個(gè)新的Ubuntu6.10,然后按照Wiki里的幫助先配置好了源、輸入法、中文環(huán)境等。然后開始來配置編譯環(huán)境。
          (1)配置GCC
          剛裝好的GCC什么都不能編譯,因?yàn)闆]有一些必須的頭文件,所以要安裝build-essential,安裝了這個(gè)包會(huì)安裝上g++,libc6-dev,linux-libc-dev,libstdc++6-4.1-dev等好多必須的軟件和頭文件。
          代碼:
          sudo?apt-get?install?build-essentia
          安裝完成后寫一個(gè)C語言程序testc.c測(cè)試一下。
          代碼:
          #include<stdio.h>
          int?main()
          {
          ???printf("Hello?Ubuntu!\n");
          ???return?0;
          }
          編譯
          $?gcc?testc.c?-o?testc
          $?./testc
          顯示
          Hello?Ubuntu!
          (2)安裝GTK環(huán)境
          安裝GTK環(huán)境只要安裝一個(gè) gnome-?core-devel就可以了,里面集成了很多其他的包。除此之外還要轉(zhuǎn)一些其他的東西,如libglib2.0-doc、 libgtk2.0-doc幫助文檔,devhelp幫助文檔查看,glade-gnome、glade-common、glade-doc圖形界面設(shè)計(jì) 等。
          代碼:

          sudo?apt-get?install?gnome-core-devel
          sudo?apt-get?install?libglib2.0-doc?libgtk2.0-doc
          sudo?apt-get?install?devhelp
          sudo?apt-get?install?glade-gnome?glade-common?glade-doc
          安裝完成后我們也同樣做個(gè)測(cè)試程序
          代碼:

          #include<gtk/gtk.h>
          void?hello(GtkWidget?*widget,gpointer?data)
          {
          g_print("Hello?Ubuntu!\n");
          }
          gint?delete_event(GtkWidget?*widget,GdkEvent?*event,gpointer?data)
          {
          g_print?("delete?event?occurred\n");
          return(TRUE);
          }
          void?destroy(GtkWidget?*widget,gpointer?data)
          {
          gtk_main_quit();
          }
          int?main(?int?argc,?char?*argv[]?)
          {
          GtkWidget?*window;
          GtkWidget?*button;
          gtk_init?(
          &argc,?&argv);
          window=gtk_window_new?(GTK_WINDOW_TOPLEVEL);
          gtk_signal_connect?(GTK_OBJECT(window),"delete_event",GTK_SIGNAL_FUNC(delete_event),NULL);
          gtk_signal_connect?(GTK_OBJECT?(window),?"destroy",GTK_SIGNAL_FUNC?(destroy),?NULL);
          gtk_container_set_border_width?(GTK_CONTAINER?(window),?10);
          button?=?gtk_button_new_with_label?("Hello?Ubuntu!");
          gtk_signal_connect?(GTK_OBJECT?(button),?"clicked",GTK_SIGNAL_FUNC?(hello),?NULL);
          gtk_signal_connect_object?(GTK_OBJECT?(button),?"clicked",GTK_SIGNAL_FUNC?(gtk_widget_destroy),GTK_OBJECT?(window));
          gtk_container_add?(GTK_CONTAINER?(window),?button);
          gtk_widget_show?(button);
          gtk_widget_show?(window);???/*顯示一個(gè)窗口*/
          gtk_main();???/*進(jìn)入主循環(huán)*/
          return(0);
          }
          用下面命令編譯運(yùn)行?
          $?gcc?gtkhello.c?-o?gtktest?`pkg-config?--cflags?--libs?gtk+-2.0`
          $?./gtktest?
          5、
          java 開發(fā)環(huán)境:
          ?sudo?apt-get?install?sun-java5-jdk
          安裝完畢之后,選擇默認(rèn) java:
          sudo?update-alternatives?--config?java?
          然后配置環(huán)境變量:
          ?sudo?vim?/etc/environment?
          在其中添加如下兩行:
          CLASSPATH=/usr/lib/jvm/java-1.5.0-sun/lib
          JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun

          posted @ 2007-02-17 14:34 滿山紅葉 閱讀(715) | 評(píng)論 (16)編輯 收藏

          2007年2月10日 #

          Hello,World in Hibernate 入門

          本文介紹如何用hibernate寫一個(gè)hello world 程序,以及說明Hibernate下的對(duì)象的識(shí)別。
          1、配置文件hibernate.cfg.xml:

          <? xml?version = ' 1.0 ' ?encoding = ' utf-8 ' ?>
          <! DOCTYPE?hibernate - configuration?PUBLIC
          ????????
          " -//Hibernate/Hibernate?Configuration?DTD?3.0//EN "
          ????????
          " http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd " >

          < hibernate - configuration >

          ????
          < session - factory >

          ????????
          <!-- ?Database?connection?settings? -->
          ????????
          < property?name = " connection.driver_class " > com.mysql.jdbc.Driver </ property >
          ????????
          < property?name = " connection.url " > jdbc:mysql: // localhost:3306/eg</property>
          ???????? < property?name = " connection.username " > root </ property >
          ????????
          < property?name = " connection.password " > 4864452 </ property >

          ????????
          <!-- ?JDBC?connection?pool?(use?the?built - in)? -->
          ????????
          < property?name = " connection.pool_size " > 1 </ property >

          ????????
          <!-- ?SQL?dialect? -->
          ????????
          < property?name = " dialect " > org.hibernate.dialect.MySQLInnoDBDialect </ property >

          ????????
          <!-- ?Enable?Hibernate ' s?automatic?session?context?management?-->
          ???????? < property?name = " current_session_context_class " > thread </ property >

          ????????
          <!-- ?Disable?the?second - level?cache?? -->
          ????????
          < property?name = " cache.provider_class " > org.hibernate.cache.NoCacheProvider </ property >

          ????????
          <!-- ?Echo?all?executed?SQL?to?stdout? -->
          ????????
          < property?name = " show_sql " > true </ property >

          ????????
          <!-- ?Drop?and?re - create?the?database?schema?on?startup?
          ????????
          < property?name = " hbm2ddl.auto " > create </ property >
          ?????????
          -->
          ????
          ????????
          < mapping?resource = " eg/Message.hbm.xml " />
          ????????
          ????????
          ????
          </ session - factory >

          </ hibernate - configuration >

          2、源文件:

          package ?eg;

          public ? class ?Message? {
          ????
          private ?Long?id;
          ????
          private ?String?text;
          ?????????????
          ????
          private ?Message?nextMessage;

          ????
          public ?Message()? {}
          ????
          public ?Message(String?text) {
          ????????
          this .text = text;
          ????}

          ????
          ????
          public ? void ?setId(Long?id)? {
          ????????
          this .id? = ?id;?
          ????}


          ????
          public ? void ?setText(String?text)? {
          ????????
          this .text? = ?text;?
          ????}


          ????
          public ? void ?setNextMessage(Message?nextMessage)? {
          ????????
          this .nextMessage? = ?nextMessage;?
          ????}

          ???????
          public ?Long?getId()? {
          ????????
          return ?( this .id);?
          ????}

          ???????
          public ?String?getText()? {
          ????????
          return ?( this .text);?
          ????}

          ???????
          public ?Message?getNextMessage()? {
          ????????
          return ?( this .nextMessage);?
          ????}
          ?
          }

          3、配置文件:Messsage.hbm.xml

          <? xml?version = " 1.0 " ?encoding = " utf-8 " ?>

          <! DOCTYPE?hibernate - mapping?PUBLIC
          ????
          " -//Hibernate/Hibernate?Mapping?DTD?3.0//EN " ?
          ????
          " http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd " >

          < hibernate - mapping >
          ????
          < class
          ????????name
          =" eg.Message "
          ????????table
          = " MESSAGE "
          ????
          >

          ????????
          < id
          ????????????name
          = " id "
          ????????????column
          = " MESSAGE_ID "
          ????????????type
          = " java.lang.Long "
          ????????
          >
          ????????????
          < generator? class = " native " />
          ?????????????????????????
          ????????
          </ id >
          ????????
          < property
          ????????????name
          = " text "
          ????????????type
          = " java.lang.String "
          ????????????update
          = " true "
          ????????????insert
          = " true "
          ????????????column
          = " MESSAGE_TEXT "
          ????????
          />

          ????????
          < many - to - one
          ????????????name
          = " nextMessage "
          ????????????
          class = " jmuse.eg.Message "
          ????????????cascade
          = " all "
          ????????????outer
          - join = " auto "
          ????????????update
          = " true "
          ????????????insert
          = " true "
          ????????????column
          = " NEXT_MESSAGE_ID "
          ????????
          />

          ??????
          </ class >

          </ hibernate - mapping >

          4、最后的包結(jié)構(gòu):

          + lib?
          ?????antlr.jar?
          ?????cglib.jar?
          ?????asm.jar?
          ?????asm
          - attrs.jars?
          ?????commons
          - collections.jar?
          ?????commons
          - logging.jar?
          ?????hibernate3.jar?
          ?????jta.jar?
          ?????dom4j.jar?
          ?????log4j.jar?
          +src?
          ????
          + eg
          ???????Message.java
          ???????Message.hbm.xml
          ???????TestMessage.java
          ?????hibernate.cfg.ml
          ?????log4j.properties

          5、測(cè)試:

          ?session.beginTransaction();
          ????????Message?m
          = new ?Message( " hello,world " );
          ????????session.save(m);
          ????????session.getTransaction().commit();
          ????????session.close();

          ?你會(huì)發(fā)現(xiàn)在數(shù)據(jù)庫(kù)中有一條信息了,id=1
          Hibernate的對(duì)象識(shí)別是通過對(duì)象的Id 來識(shí)別的:
          如:

          我們剛才在數(shù)據(jù)庫(kù)中保存了一個(gè)Id為1的Message對(duì)象。
          如果:
          session.beginTraction();
          Message?m
          = new ?Message();
          m.setId(
          new ?Long( 1 ));
          m.setText(
          " This?is?another?greeting " );
          session.saveOrUpdate(m);
          sesion.getTraction.commit();
          你會(huì)發(fā)現(xiàn)Hibernate會(huì)自動(dòng)的把剛才的對(duì)象進(jìn)行更新,而不是保存一個(gè)新的對(duì)象。
          這個(gè)例子有點(diǎn)極端,呵呵。能說明問題就可以了。

          posted @ 2007-02-10 17:42 滿山紅葉 閱讀(575) | 評(píng)論 (0)編輯 收藏

          對(duì)象的存儲(chǔ)和關(guān)系型數(shù)據(jù)庫(kù)

          ORM 的原則是將一個(gè)類映射到一張表上,然而對(duì)象和關(guān)系型數(shù)據(jù)庫(kù)之間有一點(diǎn)的差異。
          對(duì)象和對(duì)象之間的關(guān)系有一對(duì)一,一對(duì)多,多對(duì)多。這三個(gè)關(guān)系的關(guān)系的存儲(chǔ)是有差異的。
          1、一對(duì)一:我們可以用兩張表分別表示兩個(gè)類。他們之間的關(guān)系我們可以用主關(guān)鍵字或者外關(guān)鍵字來表示。然而這里有一個(gè)粒度的問題(The problem of granularity )。關(guān)于粒度問題見第4點(diǎn)。
          2、一對(duì)多:我們也可以用兩張表來表示兩個(gè)類。他們的關(guān)系我們可以用外鍵來關(guān)聯(lián)。
          3、多對(duì)多:我們可以用兩張表來表示這兩個(gè)類。用第三張表來表示他們之間的關(guān)系。
          4、關(guān)于問題的粒度:
          ??????如:一個(gè)用戶和一個(gè)地址之間的關(guān)系。當(dāng)然我們可以用一對(duì)一的方法來解決。
          然而這樣是否合理?也許最好的方法是在數(shù)據(jù)庫(kù)中增加一個(gè)新的數(shù)據(jù)類型Address(country state city zipcode etc.)。這樣我們就很容易把這個(gè)粒度問題解決了。不幸的是,數(shù)據(jù)庫(kù)是不允許自定義類型的(也許現(xiàn)在的數(shù)據(jù)庫(kù)可以,鄙人不太清楚,呵呵)。Hibernate 對(duì)這個(gè)問題有了很好的解決。見以后的文章。
          5、對(duì)象之間可以有繼承的關(guān)系,這是數(shù)據(jù)庫(kù)望洋興嘆的。Hibernate 對(duì)這個(gè)問題有了很好的解決。見以后的文章。
          6、對(duì)象的身份識(shí)別問題。
          ??? 大家都知道,java中的對(duì)象識(shí)別是用equals()和haseCode()來實(shí)現(xiàn)。
          ???舉例:

          package ?jmuse.eg;
          /**
          ?*@hibernate.class?table="MESSAGE"
          ?*
          ?
          */


          public ? class ?Message? {
          ????
          private ?Long?id;
          ????
          private ?String?text;
          ????
          private ?String?string;
          ????
          public ? void ?setString(String?s) {
          ????????string
          = s;
          ????}

          ????
          /**
          ?????*@hibernate.property?
          ?????*
          ?????
          */

          ?????
          public ?String?getString() {
          ????????
          return ? this .string;
          ????}

          ????
          ????
          private ?Message?nextMessage;
          ????
          public ?Message()? {}
          ????
          public ?Message(String?text) {
          ????????
          this .text = text;
          ????}

          ????
          ????
          public ? void ?setId(Long?id)? {
          ????????
          this .id? = ?id;?
          ????}


          ????
          public ? void ?setText(String?text)? {
          ????????
          this .text? = ?text;?
          ????}


          ????
          public ? void ?setNextMessage(Message?nextMessage)? {
          ????????
          this .nextMessage? = ?nextMessage;?
          ????}

          ????
          /**
          ?????*@hibernate.id?column="MESSAGE_ID"?generator-class="native"
          ?????*
          ?????
          */

          ????
          public ?Long?getId()? {
          ????????
          return ?( this .id);?
          ????}

          ????
          /**
          ?????*@hibernate.property?column="MESSAGE_TEXT"
          ?????*
          ?????
          */

          ????
          public ?String?getText()? {
          ????????
          return ?( this .text);?
          ????}

          ????
          /**
          ?????*@hibernate.many-to-one?column="NEXT_MESSAGE_ID"?cascade="all"
          ?????*
          ?????
          */

          ????
          public ?Message?getNextMessage()? {
          ????????
          return ?( this .nextMessage);?
          ????}

          }

          這樣的類由于沒有實(shí)現(xiàn)equals()和haseCode(),所以如果用下面的代碼我們可以看到如下輸出:

          Message?m1 = new ?Message("Hello");
          Message?m2
          = new ?Message("Hello");
          if (!(m2.equals(m1)) )log.info( " m1?and?m2?are?not?idential " );
          else ?log.info( " m1?and?m2?are?identical " );

          ////////////// /out?put //////////////
          m1?and?m2?are?not?idential

          但是我們加上如下代碼:

          ? public ? boolean ?equals(Object?o) {
          ????????
          if ( this == o)? return ? true ;
          ????????
          if ( ! (o? instanceof ?Message))?
          ????????????????
          return ? false ;
          ????????
          final ?Message?m = (Message)o;
          ????????
          return ? this .getText().equals(m.getText());
          ????}

          ????
          public ? int ?hashCode() {
          ????????
          // return?text==null?System.identityHashCode(this):text.hashCode();
          ???????? int ?hase = 20 ;
          ????????
          ????????
          return ? 20 * hase + getText().hashCode();
          ????}


          //////////// out?put //////////// /
          m1?and?m2?are?identical

          這就是java的對(duì)象識(shí)別。如果你將修改后的Message對(duì)象加入到j(luò)ava.util.Set中,不管你加多少,最后size()仍然為1。
          ?那么hibernate中的對(duì)象識(shí)別如何呢?見以后文章。呵呵。

          ?

          posted @ 2007-02-10 14:44 滿山紅葉 閱讀(653) | 評(píng)論 (0)編輯 收藏

          僅列出標(biāo)題  
          主站蜘蛛池模板: 新宾| 宜春市| 都匀市| 长葛市| 综艺| 莱州市| 南汇区| 和田县| 孙吴县| 定结县| 大港区| 乌兰察布市| 灵璧县| 松滋市| 巴塘县| 天津市| 吴忠市| 故城县| 榆树市| 安西县| 井陉县| 从江县| 沛县| 扎囊县| 来安县| 双辽市| 伊通| 白银市| 东源县| 肥东县| 平谷区| 上杭县| 仁怀市| 磐石市| 西峡县| 邵阳市| 武定县| 宜城市| 郴州市| 梁平县| 高雄县|