<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,  comments - 11,  trackbacks - 0
      2011年8月17日

    > 引言
      在Jorm中,主鍵的生成策略主要有AUTO、UUID、GUID、FOREIGN、SEQUENCE、INCREMENT、IDENTITY、ASSIGNED,下面分別來(lái)講述這幾種策略的應(yīng)用場(chǎng)景

    > GenerationType.AUTO
      Jorm的默認(rèn)主鍵策略,自動(dòng)增長(zhǎng)型,自增步長(zhǎng)為1,適用數(shù)據(jù)類型int,long,如:
      private int id // 默認(rèn)策略就是AUTO,故可以不寫主鍵策略
      或
      @Id(GenerationType.AUTO) // 默認(rèn)策略可以省去不寫的哦~
      private int id

    > GenerationType.INCREMENT
      顧名思義,增長(zhǎng)型,適用數(shù)據(jù)類型int,long。自增步長(zhǎng)為1
      1> 使用默認(rèn)自增步長(zhǎng)1,如:
         @Id(GenerationType.INCREMENT)
         @Column("item_id")
         private long id;
      2> 使用自定義步長(zhǎng),如:
         @Id(value = GenerationType.INCREMENT, incrementBy=3) // 這里自增步長(zhǎng)為3,注意寫法
         private int id;

    > GenerationType.IDENTITY
      對(duì)于那些實(shí)現(xiàn)了自動(dòng)增長(zhǎng)的數(shù)據(jù)庫(kù),可以使用IDENTITY,如MySQL,SQL Server,PostreSQL,前提是
      MySQL數(shù)據(jù)庫(kù)中建表語(yǔ)句定義了主鍵為:id(你的主鍵列名) int NOT NULL AUTO_INCREMENT 或
                                                                          
    id(你的主鍵列名) bigint NOT NULL AUTO_INCREMENT
      SQL Server數(shù)據(jù)庫(kù)中建表語(yǔ)句定義了主鍵為:id int identity(xx, xx) 如此類似
      PostreSQL數(shù)據(jù)庫(kù)中建表語(yǔ)句定義了主鍵為:id bigserial  或  id serial
      使用例子
      @Id(GenerationType.IDENTITY)
      @Column("id")
      private long sid;

    > GenerationType.UUID
      與數(shù)據(jù)庫(kù)無(wú)關(guān)的策略,適用數(shù)據(jù)類型:字符串類型,適用所有數(shù)據(jù)庫(kù),長(zhǎng)度須大于或等于32
      @Id(GenerationType.UUID)
      private String id;

    > GenerationType.GUID
      與UUID有點(diǎn)類似,不過(guò)這個(gè)id值是又?jǐn)?shù)據(jù)庫(kù)來(lái)生成的,適用于數(shù)據(jù)庫(kù)MySQL、PostgreSQL、SQL Server、Oracle等
      @Id(GenerationType.GUID)
      private String id;

    > GenerationType.FOREIGN
      適用于一對(duì)一關(guān)系中引用了另一個(gè)對(duì)象的主鍵作為自己的主鍵的情形,如:
      @Id(GenerationType.FOREIGN)
      @Column("identity_number")
      private String identity;

    > GenerationType.SEQUENCE
      這個(gè)不用多說(shuō),應(yīng)用于Oracle、H2、PostgreSQL等有sequence序列功能的數(shù)據(jù)庫(kù)

    > GenerationType.ASSIGNED
      用戶自定義生成,需要由程序員手工給主鍵主動(dòng)賦值

     

    項(xiàng)目地址:http://javaclub.sourceforge.net/jorm.html
    下載地址:http://sourceforge.net/projects/javaclub/files/jorm/


    posted @ 2011-10-10 15:17 jadmin 閱讀(1492) | 評(píng)論 (3)編輯 收藏

    直接上代碼吧:

    > Demo one
    public void batch_op_one() {

        session = Jorm.getSession();
        JdbcBatcher batcher = session.createBatcher();
        batcher.addBatch("delete from t_id_auto");
        batcher.addBatch("delete from t_incre");
        batcher.addBatch("delete from t_user");
        batcher.execute();
       
        session.beginTransaction();
        long start;
        try {
            start = System.currentTimeMillis();
            String sql = "INSERT INTO t_user(sex,age,career,name,id) VALUES(?,?,?,?,?)";
            for (int i = 0; i < 100000; i++) {
                batcher.addBatch(sql, new Object[] {"男", Numbers.random(98), Strings.random(10), Strings.fixed(6), (i+1) });}
                String sqlx = "INSERT INTO t_id_auto(name, id) VALUES(?, ?)";
                for (int i = 0; i < 100000; i++) {
                    batcher.addBatch(sqlx, new Object[] {Strings.fixed(6), (i+1)});
                    if(i > 200) {
                        //Integer.parseInt("kkk");
                    }
                }
                batcher.execute();   
                System.out.println(System.currentTimeMillis() - start);
        } catch (Exception e) {
            session.rollback();
        } finally {
            session.endTransaction();
            session.close();
        }
    }

    > Demo two
    public void batch_op_two() {

        session = Jorm.getSession();
        session.beginTransaction();
        session.clean(User.class);
        JdbcBatcher batcher = session.createBatcher();
        batcher.setBatchSize(500);// 指定每批處理的記錄數(shù)
       
        User u;
        int times = 20 * 100;
        long start = System.currentTimeMillis();
        for(int i = 0; i < times; i++) {
         String sex = (i % 2 == 0 ? "男" : "女");
         u = new User(Strings.fixed(6), sex, Numbers.random(100), Strings.random(16));
         batcher.save(u);
        }
        batcher.execute();
        session.endTransaction();
        long cost = (System.currentTimeMillis() - start);
        System.out.println("Total:" + cost);
        System.out.println("Each:" + (float) cost / times);
        session.close();
    }

    項(xiàng)目地址:http://javaclub.sourceforge.net/jorm.html
    下載地址: http://sourceforge.net/projects/javaclub/files/jorm/

    posted @ 2011-10-09 20:09 jadmin 閱讀(1294) | 評(píng)論 (0)編輯 收藏
    關(guān)系數(shù)據(jù)庫(kù)不支持繼承,我們可以做如下的映射,這些映射都是犧牲關(guān)系模式的范式基礎(chǔ)的
    ?
    1, ?用一個(gè)表包含所有繼承層次的所有字段,然后標(biāo)識(shí)列來(lái)標(biāo)示是哪個(gè)類。這種映射方法最簡(jiǎn)單,但是是違反規(guī)范化的,而且有些字段要強(qiáng)制為NULL值,無(wú)法保證關(guān)系數(shù)據(jù)模型的數(shù)據(jù)完整性,這種映射方式性能最高,最簡(jiǎn)單。
    ?
    2, ?每個(gè)具體類一張表(意思就是父類不需要表),所有父屬性在具體類表中重復(fù),這種映射如果要查詢父類要全部掃描子類表,而且一旦父類變化,這些字表要全部變化。
    ?
    3, ?每個(gè)類一張表,表里只包含所屬類的屬性,然后子類和父類共享外鍵,這種映射避免了第2種的可怕的修改,但是查詢的時(shí)候要執(zhí)行連接。
    posted @ 2011-09-27 09:38 jadmin 閱讀(202) | 評(píng)論 (0)編輯 收藏

    ??????在一般情況下,在新增領(lǐng)域?qū)ο蠛螅夹枰@取對(duì)應(yīng)的主鍵值。使用應(yīng)用層來(lái)維護(hù)主鍵,在一定程度上有利于程序性能的優(yōu)化和應(yīng)用移植性的提高。在采用數(shù)據(jù)庫(kù)自增主鍵的方案里,如果JDBC驅(qū)動(dòng)不能綁定新增記錄對(duì)應(yīng)的主鍵,就需要手工執(zhí)行查詢語(yǔ)句以獲取對(duì)應(yīng)的主鍵值,對(duì)于高并發(fā)的系統(tǒng),這很容易返回錯(cuò)誤的主鍵。通過(guò)帶緩存的DataFieldMaxValueIncrementer,可以一次獲取批量的主鍵值,供多次插入領(lǐng)域?qū)ο髸r(shí)使用,它的執(zhí)行性能是很高的。

    ??????我們經(jīng)常使用數(shù)據(jù)的自增字段作為表主鍵,也即主鍵值不在應(yīng)用層產(chǎn)生,而是在新增記錄時(shí),由數(shù)據(jù)庫(kù)產(chǎn)生。這樣,應(yīng)用層在保存對(duì)象前并不知道對(duì)象主鍵值,而必須在保存數(shù)據(jù)后才能從數(shù)據(jù)庫(kù)中返回主鍵值。在很多情況下,我們需要獲取新對(duì)象持久化后的主鍵值。在Hibernate等ORM框架,新對(duì)象持久化后,Hibernate會(huì)自動(dòng)將主鍵值綁定到對(duì)象上,給程序的開發(fā)帶來(lái)了很多方便。?

    ??????在JDBC 3.0規(guī)范中,當(dāng)新增記錄時(shí),允許將數(shù)據(jù)庫(kù)自動(dòng)產(chǎn)生的主鍵值綁定到Statement或PreparedStatement中。

    ??????使用Statement時(shí),可以通過(guò)以下方法綁定主鍵值:?int executeUpdate(String sql, int autoGeneratedKeys)?

    ??????也可以通過(guò)Connection創(chuàng)建綁定自增值的PreparedStatement:?PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)?

    ??????當(dāng)autoGeneratedKeys參數(shù)設(shè)置為Statement.RETURN_GENERATED_KEYS值時(shí)即可綁定數(shù)據(jù)庫(kù)產(chǎn)生的主鍵值,設(shè)置為Statement.NO_GENERATED_KEYS時(shí),不綁定主鍵值。下面的代碼演示了Statement綁定并獲取數(shù)據(jù)庫(kù)產(chǎn)生的主鍵值的過(guò)程:

    ????? Statement stmt = conn.createStatement();
    ????? String sql = "INSERT INTO t_topic(topic_title,user_id) VALUES(‘測(cè)試主題’,’123’)";
    ????? stmt.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS); // ①指定綁定表自增主鍵值
    ????? ResultSet rs = stmt.getGeneratedKeys();
    ????? if( rs.next() ) {
    ?????????? intkey = rs.getInt(); // ②獲取對(duì)應(yīng)的表自增主鍵值
    ????? }

    ??????Spring利用這一技術(shù),提供了一個(gè)可以返回新增記錄對(duì)應(yīng)主鍵值的方法:?int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)?,其中第二個(gè)參數(shù)類型org.springframework.jdbc.support.KeyHolder,它是一個(gè)回調(diào)接口,Spring使用它保存新增記錄對(duì)應(yīng)的主鍵,該接口的接口方法描述如下:?

    ??????Number getKey() throws InvalidDataAccessApiUsageException;

    ??????當(dāng)僅插入一行數(shù)據(jù),主鍵不是復(fù)合鍵且是數(shù)字類型時(shí),通過(guò)該方法可以直接返回新的主鍵值。如果是復(fù)合主鍵,或者有多個(gè)主鍵返回時(shí),該方法拋出 InvalidDataAccessApiUsageException。該方法是最常用的方法,因?yàn)橐话闱闆r下,我們一次僅插入一條數(shù)據(jù)并且主鍵字段類型為數(shù)字類型;?

    ??????如果是復(fù)合主鍵,則列名和列值構(gòu)成Map中的一個(gè)Entry。如果返回的是多個(gè)主鍵,則拋出InvalidDataAccessApiUsageException異常;?

    ??????Map getKeys() throws InvalidDataAccessApiUsageException;

    ??????如果返回多個(gè)主鍵,即PreparedStatement新增了多條記錄,則每一個(gè)主鍵對(duì)應(yīng)一個(gè)Map,多個(gè)Map構(gòu)成一個(gè)List。

    ??????List getKeyList():?

    ??????Spring為KeyHolder接口指代了一個(gè)通用的實(shí)現(xiàn)類GeneratedKeyHolder,該類返回新增記錄時(shí)的自增長(zhǎng)主鍵值。假設(shè)我們希望在新增論壇板塊對(duì)象后,希望將主鍵值加載到對(duì)象中,則可以按以下代碼進(jìn)行調(diào)整:

    ????? public voidaddForum(final Forum forum) {
    ??????????? final String sql = "INSERT INTO t_forum(forum_name,forum_desc) VALUES(?,?)";
    ??????????? KeyHolder keyHolder = newGeneratedKeyHolder(); // ①創(chuàng)建一個(gè)主鍵執(zhí)有者
    ??????????? getJdbcTemplate().update(newPreparedStatementCreator() {
    ????????????????? public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
    ??????????????????????? PreparedStatement ps = conn.prepareStatement(sql);
    ??????????????????????? ps.setString(1, forum.getForumName());
    ??????????????????????? ps.setString(2, forum.getForumDesc());
    ??????????????????????? returnps;
    ????????????????? }
    ??????????? }, keyHolder);
    ??????????? forum.setForumId(keyHolder.getKey().intValue()); // ②從主鍵執(zhí)有者中獲取主鍵
    ????? }

    ??????這樣,在調(diào)用addForum(Forum forum)新增forum領(lǐng)域?qū)ο蠛螅琭orum將擁有對(duì)應(yīng)的主鍵值,方便后繼的使用。在JDBC 3.0之前的版本中,PreparedStatement不能綁定主鍵,如果采用表自增鍵(如MySQL的auto increment或SQLServer的identity)將給獲取正確的主鍵值帶來(lái)挑戰(zhàn)——因?yàn)槟惚仨氃诓迦霐?shù)據(jù)后,馬上執(zhí)行另一條獲取新增主鍵的查詢語(yǔ)句。下面給出了不同數(shù)據(jù)庫(kù)獲取最新自增主鍵值的查詢語(yǔ)句:?

    posted @ 2011-09-25 14:27 jadmin 閱讀(992) | 評(píng)論 (0)編輯 收藏

    1) Assigned
    主鍵由外部程序負(fù)責(zé)生成,無(wú)需Hibernate參與。


    2) hilo
    通過(guò)hi/lo 算法實(shí)現(xiàn)的主鍵生成機(jī)制,需要額外的數(shù)據(jù)庫(kù)表保存主鍵生成歷史狀態(tài)。


    3) seqhilo
    與hilo 類似,通過(guò)hi/lo 算法實(shí)現(xiàn)的主鍵生成機(jī)制,只是主鍵歷史狀態(tài)保存在Sequence中,適用于支持Sequence的數(shù)據(jù)庫(kù),如Oracle。


    4) increment
    主鍵按數(shù)值順序遞增。此方式的實(shí)現(xiàn)機(jī)制為在當(dāng)前應(yīng)用實(shí)例中維持一個(gè)變量,以保存著當(dāng)前的最大值,之后每次需要生成主鍵的時(shí)候?qū)⒋酥导?作為主鍵。 這種方式可能產(chǎn)生的問(wèn)題是:如果當(dāng)前有多個(gè)實(shí)例訪問(wèn)同一個(gè)數(shù)據(jù)庫(kù),那么由于各個(gè)實(shí)例各自維護(hù)主鍵狀態(tài),不同實(shí)例可能生成同樣的主鍵,從而造成主鍵重復(fù)異常。因此,如果同一數(shù)據(jù)庫(kù)有多個(gè)實(shí)例訪問(wèn),此方式必須避免使用。


    5) identity
    采用數(shù)據(jù)庫(kù)提供的主鍵生成機(jī)制。如DB2、SQL Server、MySQL中的主鍵生成機(jī)制。


    6) sequence
    采用數(shù)據(jù)庫(kù)提供的sequence 機(jī)制生成主鍵。如Oralce 中的Sequence。


    7) native
    由Hibernate根據(jù)底層數(shù)據(jù)庫(kù)自行判斷采用identity、hilo、sequence其中一種作為主鍵生成方式。


    8) uuid.hex
    由Hibernate基于128 位唯一值產(chǎn)生算法生成16 進(jìn)制數(shù)值(編碼后以長(zhǎng)度32 的字符串表示)作為主鍵。


    9) uuid.string
    與uuid.hex 類似,只是生成的主鍵未進(jìn)行編碼(長(zhǎng)度16)。在某些數(shù)據(jù)庫(kù)中可能出現(xiàn)問(wèn)題(如PostgreSQL)。


    10) foreign
    使用外部表的字段作為主鍵。一般而言,利用uuid.hex方式生成主鍵將提供最好的性能和數(shù)據(jù)庫(kù)平臺(tái)適應(yīng)性。
    另外由于常用的數(shù)據(jù)庫(kù),如Oracle、DB2、SQLServer、MySql 等,都提供了易用的主鍵生成機(jī)制(Auto-Increase 字段或者Sequence)。我們可以在數(shù)據(jù)庫(kù)提供的主鍵生成機(jī)制上,采用generator-class=native的主鍵生成方式。不過(guò)值得注意的是,一些數(shù)據(jù)庫(kù)提供的主鍵生成機(jī)制在效率上未必最佳,


    大量并發(fā)insert數(shù)據(jù)時(shí)可能會(huì)引起表之間的互鎖。數(shù)據(jù)庫(kù)提供的主鍵生成機(jī)制,往往是通過(guò)在一個(gè)內(nèi)部表中保存當(dāng)前主鍵狀態(tài)(如對(duì)于自增型主鍵而言,此內(nèi)部表中就維護(hù)著當(dāng)前的最大值和遞增量), 之后每次插入數(shù)據(jù)會(huì)讀取這個(gè)最大值,然后加上遞增量作為新記錄的主鍵,之后再把這個(gè)新的最大值更新回內(nèi)部表中,這樣,一次Insert操作可能導(dǎo)致數(shù)據(jù)庫(kù)內(nèi)部多次表讀寫操作,同時(shí)伴隨的還有數(shù)據(jù)的加鎖解鎖操作,這對(duì)性能產(chǎn)生了較大影響。 因此,對(duì)于并發(fā)Insert要求較高的系統(tǒng),推薦采用uuid.hex 作為主鍵生成機(jī)制。


    如果需要采用定制的主鍵生成算法,則在此處配置主鍵生成器,主鍵生成器須實(shí)現(xiàn)org.hibernate.id.IdentifierGenerator 接口

    ?

    關(guān)鍵詞: Hibernate? 主鍵?? 主鍵生成方式? IdentifierGenerator

    ?

    posted @ 2011-09-25 13:47 jadmin 閱讀(1007) | 評(píng)論 (0)編輯 收藏
         摘要:   閱讀全文
    posted @ 2011-09-23 16:17 jadmin 閱讀(1272) | 評(píng)論 (1)編輯 收藏

    http://www.oschina.net/news/21642/jdbc-orm-framework-1-0-6

    主要更新:
    ----------------------------------------
     * [35] fix: oracle下一個(gè)分頁(yè)取limit數(shù)錯(cuò)誤的bug.
     * [34] fix: oracle下檢測(cè)是否支持Savepoints時(shí),一個(gè)未捕獲的異常.
     * [33] add: 對(duì)bonecp的支持
     * [32] add: 對(duì)proxool的支持
     * [31] add: 對(duì)commons-dbcp的支持
     * [30] fix: classpath沒(méi)有config.properties文件會(huì)報(bào)錯(cuò)


    posted @ 2011-09-23 10:53 jadmin 閱讀(201) | 評(píng)論 (0)編輯 收藏
    > 引言
    有時(shí)候我們有這樣的需求,對(duì)象有一個(gè)屬性可能有多個(gè)值,需要在數(shù)據(jù)庫(kù)中作為一個(gè)字段存儲(chǔ)

    還是以User為例,career存儲(chǔ)多個(gè)職業(yè)

    > 建表
    以MySQL為例,執(zhí)行下面的sql建立數(shù)據(jù)表
    CREATE TABLE `t_user` (                
            `id` int(11) NOT NULL,               
            `name` varchar(50) DEFAULT NULL,     
            `sex` char(4) DEFAULT NULL,          
            `age` int(11) DEFAULT NULL,          
            `career` varchar(100) DEFAULT NULL,  
            PRIMARY KEY (`id`)                   
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    > 代碼
    實(shí)體類 User.java
    @Entity(table = "t_user")
    @PK(value 
    = "id")
    public class User implements Serializable {

        
    /** desc */
        
    private static final long serialVersionUID = -4750351638245912867L;

        @Id
        
    private int id;

        
    private String name;

        
    private String sex;

        
    private Integer age;

        @Basic(processor
    =DefinedFieldProcessor.class)
        
    private String[] career;

        @NoColumn
        
    private int kvalue;

        
    public JawaUser() {
            
    super();
        }

        
    public JawaUser(String name, String sex, Integer age, String[] career) {
            
    super();
            
    this.name = name;
            
    this.sex = sex;
            
    this.age = age;
            
    this.career = career;
        }

        
    public int getId() {
            
    return id;
        }

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

        
    public String getName() {
            
    return name;
        }

        
    public void setName(String name) {
            
    this.name = name;
        }

        
    public String getSex() {
            
    return sex;
        }

        
    public void setSex(String sex) {
            
    this.sex = sex;
        }

        
    public Integer getAge() {
            
    return age;
        }

        
    public void setAge(Integer age) {
            
    this.age = age;
        }

        
    public String[] getCareer() {
            
    return career;
        }

        
    public void setCareer(String[] career) {
            
    this.career = career;
        }

        
    public int getKvalue() {
            
    return kvalue;
        }

        
    public void setKvalue(int kvalue) {
            
    this.kvalue = kvalue;
        }

        
    public String toString() {
            
    return "User [age=" + age + ", career=" + Arrays.toString(career)
                    
    + ", id=" + id + ", kvalue=" + kvalue + ", name=" + name
                    
    + ", sex=" + sex + "]";
        }
    }
    屬性字段處理類 DefinedFieldProcessor.java

    import java.lang.reflect.Field;
    import java.sql.ResultSet;
    import java.sql.SQLException;

    import org.javaclub.jorm.Session;
    import org.javaclub.jorm.common.CommonUtil;
    import org.javaclub.jorm.common.Reflections;
    import org.javaclub.jorm.jdbc.process.FieldProcessor;

    public
     class DefinedFieldProcessor implements FieldProcessor {

        
    public Object insert(Session session, Object entity, Field field) {
            String[] crs 
    = (String[]) Reflections.getFieldValue(entity, field);
            
    if(!CommonUtil.isEmpty(crs)) {
                StringBuilder sbf 
    = new StringBuilder();
                
    for (int i = 0; i < crs.length; i++) {
                    
    if(i > 0) {
                        sbf.append(
    ",");
                    }
                    sbf.append(crs[i]);
                }
                
    return sbf.toString();
            }
            
    return "";
        }

        
    public void load(Session session, Object entity, Field field, ResultSet rs,
                
    int idx) throws SQLException {
            String str 
    = rs.getString(idx);
            String[] crs 
    = str.split(",");
            Reflections.setFieldValue(entity, field, crs);
        }

    }

    > 測(cè)試

    import org.javaclub.jorm.Jorm;
    import org.javaclub.jorm.Session;
    import org.javaclub.jorm.common.Numbers;
    import org.javaclub.jorm.common.Strings;
    import org.junit.AfterClass;
    import org.junit.BeforeClass;
    import org.junit.Test;

    public
     class FieldProcessorTest {

        
    static Session session;

        @BeforeClass
        
    public static void setUpBeforeClass() {
            session 
    = Jorm.getSession();
        }

        @AfterClass
        
    public static void destroy() {
            Jorm.free();
        }

        @Test
        
    public void test_save() {

            session.clean(User.
    class);
            User u;
            
    for (int i = 0; i < 100; i++) {
                String sex 
    = (i % 2 == 0 ? "" : "");
                String[] cr 
    = {};
                
    if(i % 3 == 0) {
                    cr 
    = new String[] {Strings.fixed(2), Strings.random(5), Strings.fixed(6)};
                } 
    else if(i % 3 == 1) {
                    cr 
    = new String[] {Strings.fixed(2), Strings.random(5)};
                } 
    else {
                    cr 
    = new String[] {Strings.fixed(2)};
                }
                u 
    = new User(Strings.fixed(6), sex, Numbers.random(100), cr);
                session.save(u);
            }

            
    for (int i = 0; i < 10; i++) {
                u 
    = session.read(User.class, i + 1);
                System.out.println(u);
            }
        }
    }
    posted @ 2011-09-22 20:16 jadmin 閱讀(1218) | 評(píng)論 (0)編輯 收藏

    > 準(zhǔn)備
    以MySQL為例,執(zhí)行下面的sql建立數(shù)據(jù)表
    CREATE TABLE `t_user` (                
            `id` int(11) NOT NULL,               
            `name` varchar(50) DEFAULT NULL,     
            `sex` char(4) DEFAULT NULL,          
            `age` int(11) DEFAULT NULL,          
            `career` varchar(100) DEFAULT NULL,  
            PRIMARY KEY (`id`)                   
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    > 引入jar或maven依賴,需要jar包
    gerald-jorm-1.0.5.jar 最新版本下載:http://sourceforge.net/projects/javaclub/files
    commons-logging-1.1.1.jar
    log4j-1.2.14.jar
    mysql-connector-java-5.1.6.jar
    javassist-3.11.0.GA.jar 或 cglib-nodep-2.2.2.jar (根據(jù)實(shí)際情況選擇性加入)


    > 配置文件
    在你的java工程的classpath下建立config.properties和jdbc.cfg.xml文件
    config.properties內(nèi)容:
    # 下面路徑可以根據(jù)實(shí)際情況指定,為相對(duì)classpath的路徑地址
    jdbc.config.path=jdbc.cfg.xml

    jdbc.cfg.xml內(nèi)容:
    <?xml version='1.0' encoding="UTF-8"?>
    <jdbc-configuration>

      <constant name="show_sql" value="true" />
      <constant name="jdbc.batch_size" value="600" />
      <constant name="bytecode.provider" value="cglib" />
     
      <connections default="simple">
     
        <connection name="simple">
          <property name="connection.implementation">org.javaclub.jorm.jdbc.connection.impl.SimpleConnection</property>
          <property name="connection.dialect">MySQLDialect</property>
          <property name="connection.driver">com.mysql.jdbc.Driver</property>
          <property name="connection.jdbcurl">jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=UTF-8</property>
          <property name="connection.database">test</property>
          <property name="connection.username">root</property>
          <property name="connection.password">root</property>
        </connection>

        <connection name="c3p0">
          <property name="connection.implementation">org.javaclub.jorm.jdbc.connection.impl.PooledConnection</property>
          <property name="connection.dialect">MySQLDialect</property>
          <property name="connection.driver">com.mysql.jdbc.Driver</property>
          <property name="connection.jdbcurl">jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=UTF-8</property>
          <property name="connection.database">test</property>
          <property name="connection.username">root</property>
          <property name="connection.password">root</property>
          <property name="connection.pool.min">1</property>
          <property name="connection.pool.max">8</property>
          <property name="connection.test.sql">select 1</property>
        </connection>
        
      </connections>

    </jdbc-configuration>


    > 實(shí)體類User.java
    @PK(value = "id")
    @Entity(table="t_user")
    public class User {
        
        @Id
        private int id;

        private String name;

        private String sex;

        private Integer age;

        private String career;
        
        @NoColumn
        private int kvalue;
        
        public User() {
            super();
        }

        public User(String name, String sex, Integer age, String career) {
            super();
            this.name = name;
            this.sex = sex;
            this.age = age;
            this.career = career;
        }

        public User(Integer id, String name, String sex, Integer age, String career) {
            super();
            this.id = id;
            this.name = name;
            this.sex = sex;
            this.age = age;
            this.career = career;
        }

        public int getId() {
            return id;
        }

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

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getSex() {
            return sex;
        }

        public void setSex(String sex) {
            this.sex = sex;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        public String getCareer() {
            return career;
        }

        public void setCareer(String career) {
            this.career = career;
        }

        public int getKvalue() {
            return kvalue;
        }

        public void setKvalue(int kvalue) {
            this.kvalue = kvalue;
        }

        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("[" + id + ", " + name + ", " + sex + ", " + age + ", " + career + "]");
            return sb.toString();
        }

    }

    這里數(shù)據(jù)庫(kù)字段和java實(shí)體類User的屬性在命名上是一致的,如果不一致,比如如果表創(chuàng)建sql為:
    CREATE TABLE `t_user` (                
            `user_id` int(11) NOT NULL,               
            `user_name` varchar(50) DEFAULT NULL,     
            `sex` char(4) DEFAULT NULL,          
            `col_age` int(11) DEFAULT NULL,          
            `career_job` varchar(100) DEFAULT NULL,  
            PRIMARY KEY (`id`)                   
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    那么對(duì)應(yīng)的實(shí)體User應(yīng)該寫成:
    @PK(value = "id")
    @Entity(table="t_user")
    public class User {
        
        @Id
        @Column("user_id")
        private int id;

        @Column("user_name")
        private String name;
            
        // 與數(shù)據(jù)庫(kù)字段命名一致,可以不指定@Column
        private String sex;

        @Column("col_age")
        private Integer age;

        @Column("career_job")
        private String career;
        
        @NoColumn
        private int kvalue;
        
        public User() {
            super();
        }

        public User(String name, String sex, Integer age, String career) {
            super();
            this.name = name;
            this.sex = sex;
            this.age = age;
            this.career = career;
        }

        public User(Integer id, String name, String sex, Integer age, String career) {
            super();
            this.id = id;
            this.name = name;
            this.sex = sex;
            this.age = age;
            this.career = career;
        }

        public int getId() {
            return id;
        }

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

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getSex() {
            return sex;
        }

        public void setSex(String sex) {
            this.sex = sex;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        public String getCareer() {
            return career;
        }

        public void setCareer(String career) {
            this.career = career;
        }

        public int getKvalue() {
            return kvalue;
        }

        public void setKvalue(int kvalue) {
            this.kvalue = kvalue;
        }

        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("[" + id + ", " + name + ", " + sex + ", " + age + ", " + career + "]");
            return sb.toString();
        }

    }


    > 對(duì)User的增刪查改,UserCrudTest.java,記得引入junit-4.8.2.jar
    public class UserCrudTest {

        static Session session;
        
        @BeforeClass
        public static void before() {
            session = Jorm.getSession();
        }
        
        @AfterClass
        public static void after() {
            Jorm.free();
        }
        
        @Test
        public void save_user() {
            session.clean(User.class);
            User user = null;
            for (int i = 0; i < 600; i++) {
                String sex = (i % 2 == 0 ? "男" : "女");
                user = new User(Strings.fixed(5), sex, Numbers.random(98), Strings.random(8));
                session.save(user);
            }
        }
        
        @Test // 批量保存
        public void batch_save_user() {
            session.clean(User.class);
            JdbcBatcher batcher = session.createBatcher();
            User user = null;
            for (int i = 0; i < 600; i++) {
                String sex = (i % 2 == 0 ? "男" : "女");
                user = new User(Strings.fixed(5), sex, Numbers.random(98), Strings.random(8));
                batcher.save(user);
            }
            batcher.execute();
        }
        
        @Test
        public void loadUser() {
            User user = session.read(User.class, 1);
            // 這里user是一個(gè)代理對(duì)象,因?yàn)?#64;Entity(table="t_user", lazy = true)
            System.out.println(user.getCareer());// 發(fā)出查詢sql
        }
        
        @Test
        public void deletUser() {
            User user = session.read(User.class, 1);
            if(null != user) {
                session.delete(user);
            }
            user = session.read(User.class, 1);
            System.out.println(user);
        }
        
        @Test
        public void test_update_proxy() {
            
            User u;
            u = session.read(User.class, 2);
            Assert.assertNotNull(u);
            Assert.assertTrue(u instanceof JormProxy);
            
            u.setName("Gerald.Chen");
            session.update(u);
            System.out.println(u.getName());
            u = session.read(User.class, 2);
            Assert.assertTrue("Gerald.Chen".equals(u.getName()));
        }
        
        @Test
        public void queryUser() {
            SqlParams<User> params = new SqlParams<User>();
            params.setObjectClass(User.class);
            params.setFirstResult(8);
            params.setMaxResults(20);
            List<User> users = session.list(params);
            System.out.println(users.size());
            System.out.println(users);
        }
        
    }

    posted @ 2011-09-21 18:42 jadmin 閱讀(1414) | 評(píng)論 (5)編輯 收藏

    > 特點(diǎn)
      1.支持多數(shù)據(jù)源管理和配置
      2.自動(dòng)封裝Entity
      3.支持事務(wù)
      4.支持存儲(chǔ)過(guò)程的方便調(diào)用
      5.支持lazy加載
      6.支持分頁(yè)查詢
      7.支持多種數(shù)據(jù)庫(kù)H2,MySQL,Oracle,PostgrSQL,SQLServer

    > 要求
      1.JDK 1.5 or later
      2.如需要lazy加載,需要引入cglib或javaassit,具體可配置

    > 示例
      1.添加
      Session session = Jorm.getSession();
      User u = new User("Gerald.Chen", "男", 21, "job");;
      session.save(u);

      2.刪除
      session.clean(User.class);// 清空表
      session.delete(User.class, "id > 100");// 指定條件刪除

      session.delete(user);

      3.查詢
      User user = session.read(User.class, 1);// 根據(jù)主鍵加載

      // 加載第一個(gè)
      User user = session.loadFirst(User.class, "(SELECT * FROM t_user WHERE id > ?)", 88);

      // 分頁(yè)查詢
      SqlParams<User> params = new SqlParams<User>("SELECT * FROM t_user WHERE id > ?", new Object[] { 6 });
      params.setObjectClass(User.class);
      params.setFirstResult(3);
      params.setMaxResults(10);
      List<User> users = session.list(params);

      // 查詢單個(gè)屬性
      String sql = "SELECT name FROM t_user WHERE id = 28";
      String name = session.queryUniqueObject(sql);

      // 查詢屬性列表
      List<String> names = session.list(String.class, "SELECT name FROM t_user WHERE id > ?", 200);
      List<Integer> ages = session.list(int.class, "SELECT age FROM t_user WHERE age > 18");

      4.存儲(chǔ)過(guò)程
      final String pro = "{? = call hello_proc(?)}";
      String r = session.call(new ProcedureCaller() {
                
         public CallableStatement prepare() throws SQLException {
        CallableStatement cs = this.getSession().getConnection().prepareCall(pro);
        cs.setString(2, "World");
        cs.registerOutParameter(1, Types.CHAR);
        return cs;
         }
                
         public String callback(CallableStatement cs) throws SQLException {
        cs.execute();
        return cs.getString(1);
         }
      });

      5.事務(wù)
      session.clean(User.class);
      User u;
      session.beginTransaction();
      try {
        for(int i = 0; i < 1000; i++) {
            String sex = (i % 2 == 0 ? "男" : "女");
            u = new User(Strings.fixed(6), sex, Numbers.random(100), Strings.random(16));
            session.save(u);
            if(i == 886) {
                Integer.parseInt("kkk");
            }
        }
        session.commit();
      } catch (Exception e) {
        session.rollback();
      } finally {
        session.endTransaction();
      }

    這是一個(gè)完全基于JDBC的輕量java orm framework, 目標(biāo)定位于使用方便,簡(jiǎn)單,后續(xù)會(huì)增加許多新的特性


     

    項(xiàng)目地址:http://javaclub.sourceforge.net/jorm.html

    下載地址:http://sourceforge.net/projects/javaclub/files

     

    posted @ 2011-09-20 18:52 jadmin 閱讀(261) | 評(píng)論 (0)編輯 收藏

    > 原理

    其實(shí)斷點(diǎn)續(xù)傳的原理很簡(jiǎn)單,就是在 Http 的請(qǐng)求上和一般的下載有所不同而已。
    打個(gè)比方,瀏覽器請(qǐng)求服務(wù)器上的一個(gè)文時(shí),所發(fā)出的請(qǐng)求如下:
    假設(shè)服務(wù)器域名為 wwww.sjtu.edu.cn,文件名為 down.zip。
    GET /down.zip HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
    excel, application/msword, application/vnd.ms-powerpoint, */*
    Accept-Language: zh-cn
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
    Connection: Keep-Alive

    服務(wù)器收到請(qǐng)求后,按要求尋找請(qǐng)求的文件,提取文件的信息,然后返回給瀏覽器,返回信息如下:

    200
    Content-Length=106786028
    Accept-Ranges=bytes
    Date=Mon, 30 Apr 2001 12:56:11 GMT
    ETag=W/"02ca57e173c11:95b"
    Content-Type=application/octet-stream
    Server=Microsoft-IIS/5.0
    Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT

    所謂斷點(diǎn)續(xù)傳,也就是要從文件已經(jīng)下載的地方開始繼續(xù)下載。所以在客戶端瀏覽器傳給 Web 服務(wù)器的時(shí)候要多加一條信息 -- 從哪里開始。
    下面是用自己編的一個(gè)"瀏覽器"來(lái)傳遞請(qǐng)求信息給 Web 服務(wù)器,要求從 2000070 字節(jié)開始。
    GET /down.zip HTTP/1.0
    User-Agent: NetFox
    RANGE: bytes=2000070-
    Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

    仔細(xì)看一下就會(huì)發(fā)現(xiàn)多了一行 RANGE: bytes=2000070-
    這一行的意思就是告訴服務(wù)器 down.zip 這個(gè)文件從 2000070 字節(jié)開始傳,前面的字節(jié)不用傳了。
    服務(wù)器收到這個(gè)請(qǐng)求以后,返回的信息如下:
    206
    Content-Length=106786028
    Content-Range=bytes 2000070-106786027/106786028
    Date=Mon, 30 Apr 2001 12:55:20 GMT
    ETag=W/"02ca57e173c11:95b"
    Content-Type=application/octet-stream
    Server=Microsoft-IIS/5.0
    Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT

    和前面服務(wù)器返回的信息比較一下,就會(huì)發(fā)現(xiàn)增加了一行:
    Content-Range=bytes 2000070-106786027/106786028

    返回的代碼也改為 206 了,而不再是 200 了。

    > 關(guān)鍵點(diǎn)

    (1) 用什么方法實(shí)現(xiàn)提交 RANGE: bytes=2000070-。
    當(dāng)然用最原始的 Socket 是肯定能完成的,不過(guò)那樣太費(fèi)事了,其實(shí) Java 的 net 包中提供了這種功能。代碼如下:

    URL url = new URL("http://www.sjtu.edu.cn/down.zip");
    HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();

    // 設(shè)置 User-Agent
    httpConnection.setRequestProperty("User-Agent","NetFox");
    // 設(shè)置斷點(diǎn)續(xù)傳的開始位置
    httpConnection.setRequestProperty("RANGE","bytes=2000070");
    // 獲得輸入流
    InputStream input = httpConnection.getInputStream();

    從輸入流中取出的字節(jié)流就是 down.zip 文件從 2000070 開始的字節(jié)流。大家看,其實(shí)斷點(diǎn)續(xù)傳用 Java 實(shí)現(xiàn)起來(lái)還是很簡(jiǎn)單的吧。接下來(lái)要做的事就是怎么保存獲得的流到文件中去了。

    (2)保存文件采用的方法。
    我采用的是 IO 包中的 RandAccessFile 類。
    操作相當(dāng)簡(jiǎn)單,假設(shè)從 2000070 處開始保存文件,代碼如下:
    RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw");
    long nPos = 2000070;
    // 定位文件指針到 nPos 位置
    oSavedFile.seek(nPos);
    byte[] b = new byte[1024];
    int nRead;
    // 從輸入流中讀入字節(jié)流,然后寫到文件中
    while((nRead=input.read(b,0,1024)) > 0) {
    ???? oSavedFile.write(b,0,nRead);

    }

    ?

    posted @ 2011-09-08 21:51 jadmin 閱讀(108) | 評(píng)論 (0)編輯 收藏

    SymmetricDS是一個(gè)平臺(tái)獨(dú)立的數(shù)據(jù)同步和復(fù)制的解決方案。

    配置數(shù)據(jù)模型:

    運(yùn)行時(shí)數(shù)據(jù)模型:

    posted @ 2011-09-02 09:15 jadmin 閱讀(232) | 評(píng)論 (0)編輯 收藏

    > 問(wèn)題:給40億個(gè)不重復(fù)的unsigned int的整數(shù),沒(méi)排過(guò)序的,然后再給幾個(gè)數(shù),如何快速判斷這幾個(gè)數(shù)是否在那40億個(gè)數(shù)當(dāng)中?

    > 解決:unsigned int 的取值范圍是0到2^32-1。我們可以申請(qǐng)連續(xù)的2^32/8=512M的內(nèi)存,用每一個(gè)bit對(duì)應(yīng)一個(gè)unsigned int數(shù)字。首先將512M內(nèi)存都初始化為0,然后每處理一個(gè)數(shù)字就將其對(duì)應(yīng)的bit設(shè)置為1。當(dāng)需要查詢時(shí),直接找到對(duì)應(yīng)bit,看其值是0還是1即可。

    posted @ 2011-08-30 21:01 jadmin 閱讀(142) | 評(píng)論 (0)編輯 收藏

    lazy的屬性有false、true、extra

    false和true用得比較多,extra屬性是不大容易重視的,其實(shí)它和true差不多

    extra有個(gè)小的智能的地方是,即調(diào)用集合的size/contains等方法的時(shí)候,hibernate并不會(huì)去加載整個(gè)集合的數(shù)據(jù),而是發(fā)出一條聰明的SQL語(yǔ)句,以便獲得需要的值,只有在真正需要用到這些集合元素對(duì)象數(shù)據(jù)的時(shí)候,才去發(fā)出查詢語(yǔ)句加載所有對(duì)象的數(shù)據(jù)


    posted @ 2011-08-30 20:00 jadmin 閱讀(108) | 評(píng)論 (0)編輯 收藏

    本文將介紹在Linux(Red Hat 9)環(huán)境下搭建Hadoop集群,此Hadoop集群主要由三臺(tái)機(jī)器組成,主機(jī)名分別為
    linux????? 192.168.35.101
    linux02? 192.168.35.102
    linux03? 192.168.35.103

    從map reduce計(jì)算的角度講,linux作為master節(jié)點(diǎn),linux02和linux03作為slave節(jié)點(diǎn)。
    從hdfs數(shù)據(jù)存儲(chǔ)角度講,linux作為namenode節(jié)點(diǎn),linux02和linux03作為datanode節(jié)點(diǎn)。


    一臺(tái)namenode機(jī),主機(jī)名為linux,hosts文件內(nèi)容如下:
    127.0.0.1?? ??? linux????????? localhost.localdomain????????? localhost
    192.168.35.101???? linux????????? linux.localdomain????????????? linux
    192.168.35.102???? linux02
    192.168.35.103???? linux03

    兩臺(tái)datanode機(jī),主機(jī)名為linux02和linux03
    >linux02的hosts文件
    127.0.0.1 ??? ??? linux02?????? localhost.localdomain?????? localhost
    192.168.35.102???? linux02?????? linux02.localdomain???????? linux02
    192.168.35.101???? linux
    192.168.35.103???? linux03
    >inux03的hosts文件
    127.0.0.1?? ????? ??? ?linux03????????? localhost.localdomain????????? localhost
    192.168.35.103????????? linux03??????????? linux03.localdomain??????????? linux03
    192.168.35.101? ??? ?linux
    192.168.35.102? ??? ?linux02

    1.安裝JDK
    > 從java.cun.com下載jdk-6u7-linux-i586.bin

    > ftp上傳jdk到linux的root目錄下

    > 進(jìn)入root目錄,先后執(zhí)行命令
    chmod 755 jdk-6u18-linux-i586-rpm.bin
    ./jdk-6u18-linux-i586-rpm.bin

    一路按提示下去就會(huì)安裝成功

    > 配置環(huán)境變量
    cd進(jìn)入/etc目錄,vi編輯profile文件,將下面的內(nèi)容追加到文件末尾
    export JAVA_HOME=/usr/java/jdk1.6.0_18
    export PATH=$JAVA_HOME/bin:$PATH
    export CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

    注意:三臺(tái)機(jī)器都要安裝JDK~

    2.設(shè)置Master/Slave機(jī)器之間可以通過(guò)SSH無(wú)密鑰互相訪問(wèn)
    最好三臺(tái)機(jī)器的使用相同的賬戶名,我是直接使用的root賬戶

    操作namenode機(jī)linux:
    以用戶root登錄linux,在/root目錄下執(zhí)行下述命令:
    ssh-keygen -t rsa
    一路回車下去即可在目錄/root/.ssh/下建立兩個(gè)文件id_rsa.pub和id_rsa。

    接下來(lái),需要進(jìn)入/root/.ssh目錄,執(zhí)行如下命令:
    cd .ssh

    再把is_rsa.pub文件復(fù)制到linux02和linux03機(jī)器上去。
    scp -r id_rsa.pub root@192.168.35.102:/root/.ssh/authorized_keys_01
    scp -r id_rsa.pub root@192.168.35.103:/root/.ssh/authorized_keys_01

    操作datanode機(jī)linux02:
    以用戶root登錄linux02,在目錄下執(zhí)行命令:
    ssh-keygen -t rsa
    一路回車下去即可在目錄/root/.ssh/下建立兩個(gè)文件 id_rsa.pub和id_rsa。

    接下來(lái),需要進(jìn)入/root/.ssh目錄,執(zhí)行如下命令:
    cd .ssh

    再把is_rsa.pub文件復(fù)制到namenode機(jī)linux上去。
    scp -r id_rsa.pub root@192.168.35.101:/root/.ssh/authorized_keys_02

    操作datanode機(jī)linux03:
    以用戶root登錄linux03,在目錄下執(zhí)行命令:
    ssh-keygen -t rsa
    一路回車下去即可在目錄/root/.ssh/下建立兩個(gè)文件 id_rsa.pub和id_rsa。

    接下來(lái),需要進(jìn)入/root/.ssh目錄,執(zhí)行如下命令:
    cd .ssh

    再把is_rsa.pub文件復(fù)制到namenode機(jī)linux上去。
    scp -r id_rsa.pub root@192.168.35.101:/root/.ssh/authorized_keys_03

    *******************************************************************************

    上述方式分別為linux\linux02\linux03機(jī)器生成了rsa密鑰,并且把linux的id_rsa.pub復(fù)制到linux02\linux03上去了,而把linux02和linux03上的id_rsa.pub復(fù)制到linux上去了。

    接下來(lái)還要完成如下步驟:

    linux機(jī):
    以root用戶登錄linux,并且進(jìn)入目錄/root/.ssh下,執(zhí)行如下命令:
    cat id_rsa.pub >> authorized_keys
    cat authorized_keys_02 >> authorized_keys
    cat authorized_keys_03 >> authorized_keys
    chmod 644 authorized_keys

    linux02機(jī):
    以root用戶登錄linux02,并且進(jìn)入目錄/root/.ssh下,執(zhí)行如下命令:
    cat id_rsa.pub >> authorized_keys
    cat authorized_keys_01 >> authorized_keys
    chmod 644 authorized_keys

    linux03機(jī):
    以root用戶登錄linux03,并且進(jìn)入目錄/root/.ssh下,執(zhí)行如下命令:
    cat id_rsa.pub >> authorized_keys
    cat authorized_keys_01 >> authorized_keys
    chmod 644 authorized_keys

    通過(guò)上述配置,現(xiàn)在以用戶root登錄linux機(jī),既可以無(wú)密鑰認(rèn)證方式訪問(wèn)linux02和linux03了,同樣也可以在linux02和linux03上以ssh linux方式連接到linux上進(jìn)行訪問(wèn)了。

    3.安裝和配置Hadoop
    > 在namenode機(jī)器即linux機(jī)上安裝hadoop
    我下載的是hadoop-0.20.2.tar.gz,ftp上傳到linux機(jī)的/root目錄上,解壓到安裝目錄/usr/hadoop,最終hadoop的根目錄是/usr/hadoop/hadoop-0.20.2/

    編輯/etc/profile文件,在文件尾部追加如下內(nèi)容:
    export HADOOP_HOME=/usr/hadoop/hadoop-0.20.2
    export PATH=$HADOOP_HOME/bin:$PATH

    > 配置Hadoop
    core-site.xml:
    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

    <!-- Put site-specific property overrides in this file. -->
    <configuration>
    ?? ?<property>
    ??????????????? <name>fs.default.name</name>
    ??????????????? <value>hdfs://192.168.35.101:9000</value>
    ??????? </property>
    ??????? <property>
    ??????????????? <name>hadoop.tmp.dir</name>
    ??????????????? <value>/tmp/hadoop/hadoop-${user.name}</value>
    ??????? </property>
    </configuration>

    hdfs-site.xml:
    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

    <!-- Put site-specific property overrides in this file. -->
    <configuration>
    ??????? <property>
    ??????????????? <name>dfs.name.dir</name>
    ??????????????? <value>/home/hadoop/name</value>
    ??????? </property>
    ??????? <property>
    ??????????????? <name>dfs.data.dir</name>
    ??????????????? <value>/home/hadoop/data</value>
    ??????? </property>
    ??????? <property>
    ??????????????? <name>dfs.replication</name>
    ??????????????? <value>2</value>
    ??????? </property>
    </configuration>

    mapred-site.xml
    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

    <!-- Put site-specific property overrides in this file. -->
    <configuration>
    ??????? <property>
    ??????????????? <name>mapred.job.tracker</name>
    ??????????????? <value>192.168.35.101:9001</value>
    ??????? </property>
    </configuration>

    masters
    192.168.35.101

    slaves
    192.168.35.102
    192.168.35.103

    至此,hadoop的簡(jiǎn)單配置已經(jīng)完成

    > 將在namenode機(jī)器上配置好的hadoop部署到datanode機(jī)器上
    這里使用scp命令進(jìn)行遠(yuǎn)程傳輸,先后執(zhí)行命令
    scp -r /usr/hadoop/hadoop-0.20.2 root@192.168.35.102:/usr/hadoop/
    scp -r /usr/hadoop/hadoop-0.20.2 root@192.168.35.103:/usr/hadoop/

    4.測(cè)試
    以root用戶登入namenode機(jī)linux,進(jìn)入目錄/usr/hadoop/hadoop-0.20.2/
    cd /usr/hadoop/hadoop-0.20.2

    > 執(zhí)行格式化
    [root@linux hadoop-0.20.2]# bin/hadoop namenode -format
    11/07/26 21:16:03 INFO namenode.NameNode: STARTUP_MSG:
    /************************************************************
    STARTUP_MSG: Starting NameNode
    STARTUP_MSG:?? host = linux/127.0.0.1
    STARTUP_MSG:?? args = [-format]
    STARTUP_MSG:?? version = 0.20.2
    STARTUP_MSG:?? build = https://svn.apache.org/repos/asf/hadoop/common/branches/branch-0.20 -r 911707; compiled by 'chrisdo' on Fri Feb 19 08:07:34 UTC 2010
    ************************************************************/
    Re-format filesystem in /home/hadoop/name ? (Y or N) Y
    11/07/26 21:16:07 INFO namenode.FSNamesystem: fsOwner=root,root,bin,daemon,sys,adm,disk,wheel
    11/07/26 21:16:07 INFO namenode.FSNamesystem: supergroup=supergroup
    11/07/26 21:16:07 INFO namenode.FSNamesystem: isPermissionEnabled=true
    11/07/26 21:16:07 INFO common.Storage: Image file of size 94 saved in 0 seconds.
    11/07/26 21:16:07 INFO common.Storage: Storage directory /home/hadoop/name has been successfully formatted.
    11/07/26 21:16:07 INFO namenode.NameNode: SHUTDOWN_MSG:
    /************************************************************
    SHUTDOWN_MSG: Shutting down NameNode at linux/127.0.0.1
    ************************************************************/

    > 啟動(dòng)hadoop
    [root@linux hadoop-0.20.2]# bin/start-all.sh
    starting namenode, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-namenode-linux.out
    192.168.35.102: starting datanode, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-datanode-linux02.out
    192.168.35.103: starting datanode, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-datanode-linux03.out
    192.168.35.101: starting secondarynamenode, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-secondarynamenode-linux.out
    starting jobtracker, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-jobtracker-linux.out
    192.168.35.103: starting tasktracker, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-tasktracker-linux03.out
    192.168.35.102: starting tasktracker, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-tasktracker-linux02.out
    [root@linux hadoop-0.20.2]#

    > 用jps命令查看進(jìn)程
    [root@linux hadoop-0.20.2]# jps
    7118 SecondaryNameNode
    7343 Jps
    6955 NameNode
    7204 JobTracker
    [root@linux hadoop-0.20.2]#

    posted @ 2011-08-25 16:01 jadmin 閱讀(126) | 評(píng)論 (0)編輯 收藏

    引言

    Hadoop分布式文件系統(tǒng)(HDFS)被設(shè)計(jì)成適 合運(yùn)行在通用硬件(commodity hardware)上的分布式文件系統(tǒng)。它和現(xiàn)有的分布式文件系統(tǒng)有很多共同點(diǎn)。但同時(shí),它和其他的分布式文件系統(tǒng)的區(qū)別也是很明顯的。HDFS是一個(gè)高 度容錯(cuò)性的系統(tǒng),適合部署在廉價(jià)的機(jī)器上。HDFS能提供高吞吐量的數(shù)據(jù)訪問(wèn),非常適合大規(guī)模數(shù)據(jù)集上的應(yīng)用。HDFS放寬了一部分POSIX約束,來(lái)實(shí) 現(xiàn)流式讀取文件系統(tǒng)數(shù)據(jù)的目的。HDFS在最開始是作為Apache Nutch搜索引擎項(xiàng)目的基礎(chǔ)架構(gòu)而開發(fā)的。HDFS是Apache Hadoop Core項(xiàng)目的一部分。這個(gè)項(xiàng)目的地址是http://hadoop.apache.org/core/

    前提和設(shè)計(jì)目標(biāo)

    硬件錯(cuò)誤

    硬件錯(cuò)誤是常態(tài)而不是異常。HDFS可能由成百上千的服務(wù)器所構(gòu)成,每個(gè)服務(wù)器上存儲(chǔ)著文件系統(tǒng)的部分?jǐn)?shù)據(jù)。我們面對(duì)的現(xiàn)實(shí)是構(gòu)成系統(tǒng)的組件數(shù)目是巨大 的,而且任一組件都有可能失效,這意味著總是有一部分HDFS的組件是不工作的。因此錯(cuò)誤檢測(cè)和快速、自動(dòng)的恢復(fù)是HDFS最核心的架構(gòu)目標(biāo)。

    流式數(shù)據(jù)訪問(wèn)

    運(yùn)行在HDFS上的應(yīng)用和普通的應(yīng)用不同,需要流式訪問(wèn)它們的數(shù)據(jù)集。HDFS的設(shè)計(jì)中更多的考慮到了數(shù)據(jù)批處理,而不是用戶交互處理。比之?dāng)?shù)據(jù)訪問(wèn)的低 延遲問(wèn)題,更關(guān)鍵的在于數(shù)據(jù)訪問(wèn)的高吞吐量。POSIX標(biāo)準(zhǔn)設(shè)置的很多硬性約束對(duì)HDFS應(yīng)用系統(tǒng)不是必需的。為了提高數(shù)據(jù)的吞吐量,在一些關(guān)鍵方面對(duì) POSIX的語(yǔ)義做了一些修改。

    大規(guī)模數(shù)據(jù)集

    運(yùn)行在HDFS上的應(yīng)用具有很大的數(shù)據(jù)集。HDFS上的一個(gè)典型文件大小一般都在G字節(jié)至T字節(jié)。因此,HDFS被調(diào)節(jié)以支持大文件存儲(chǔ)。它應(yīng)該能提供整 體上高的數(shù)據(jù)傳輸帶寬,能在一個(gè)集群里擴(kuò)展到數(shù)百個(gè)節(jié)點(diǎn)。一個(gè)單一的HDFS實(shí)例應(yīng)該能支撐數(shù)以千萬(wàn)計(jì)的文件。

    簡(jiǎn)單的一致性模型

    HDFS應(yīng)用需要一個(gè)“一次寫入多次讀取”的文件訪問(wèn)模型。一個(gè)文件經(jīng)過(guò)創(chuàng)建、寫入和關(guān)閉之后就不需要改變。這一假設(shè)簡(jiǎn)化了數(shù)據(jù)一致性問(wèn)題,并且使高吞吐 量的數(shù)據(jù)訪問(wèn)成為可能。Map/Reduce應(yīng)用或者網(wǎng)絡(luò)爬蟲應(yīng)用都非常適合這個(gè)模型。目前還有計(jì)劃在將來(lái)擴(kuò)充這個(gè)模型,使之支持文件的附加寫操作。

    “移動(dòng)計(jì)算比移動(dòng)數(shù)據(jù)更劃算”

    一個(gè)應(yīng)用請(qǐng)求的計(jì)算,離它操作的數(shù)據(jù)越近就越高效,在數(shù)據(jù)達(dá)到海量級(jí)別的時(shí)候更是如此。因?yàn)檫@樣就能降低網(wǎng)絡(luò)阻塞的影響,提高系統(tǒng)數(shù)據(jù)的吞吐量。將計(jì)算移 動(dòng)到數(shù)據(jù)附近,比之將數(shù)據(jù)移動(dòng)到應(yīng)用所在顯然更好。HDFS為應(yīng)用提供了將它們自己移動(dòng)到數(shù)據(jù)附近的接口。

    異構(gòu)軟硬件平臺(tái)間的可移植性

    HDFS在設(shè)計(jì)的時(shí)候就考慮到平臺(tái)的可移植性。這種特性方便了HDFS作為大規(guī)模數(shù)據(jù)應(yīng)用平臺(tái)的推廣。

    Namenode 和 Datanode

    HDFS采用master/slave架構(gòu)。一個(gè)HDFS集群是由一個(gè)Namenode和一定數(shù)目的Datanodes組成。Namenode是一個(gè)中心 服務(wù)器,負(fù)責(zé)管理文件系統(tǒng)的名字空間(namespace)以及客戶端對(duì)文件的訪問(wèn)。集群中的Datanode一般是一個(gè)節(jié)點(diǎn)一個(gè),負(fù)責(zé)管理它所在節(jié)點(diǎn)上 的存儲(chǔ)。HDFS暴露了文件系統(tǒng)的名字空間,用戶能夠以文件的形式在上面存儲(chǔ)數(shù)據(jù)。從內(nèi)部看,一個(gè)文件其實(shí)被分成一個(gè)或多個(gè)數(shù)據(jù)塊,這些塊存儲(chǔ)在一組 Datanode上。Namenode執(zhí)行文件系統(tǒng)的名字空間操作,比如打開、關(guān)閉、重命名文件或目錄。它也負(fù)責(zé)確定數(shù)據(jù)塊到具體Datanode節(jié)點(diǎn)的 映射。Datanode負(fù)責(zé)處理文件系統(tǒng)客戶端的讀寫請(qǐng)求。在Namenode的統(tǒng)一調(diào)度下進(jìn)行數(shù)據(jù)塊的創(chuàng)建、刪除和復(fù)制。

    HDFS 架構(gòu)

    Namenode和Datanode被設(shè)計(jì)成可以在普通的商用機(jī)器上運(yùn)行。這些機(jī)器一般運(yùn)行著GNU/Linux操作系統(tǒng)(OS)。 HDFS采用Java語(yǔ)言開發(fā),因此任何支持Java的機(jī)器都可以部署Namenode或Datanode。由于采用了可移植性極強(qiáng)的Java語(yǔ)言,使得 HDFS可以部署到多種類型的機(jī)器上。一個(gè)典型的部署場(chǎng)景是一臺(tái)機(jī)器上只運(yùn)行一個(gè)Namenode實(shí)例,而集群中的其它機(jī)器分別運(yùn)行一個(gè)Datanode 實(shí)例。這種架構(gòu)并不排斥在一臺(tái)機(jī)器上運(yùn)行多個(gè)Datanode,只不過(guò)這樣的情況比較少見。

    集群中單一Namenode的結(jié)構(gòu)大大簡(jiǎn)化了系統(tǒng)的架構(gòu)。Namenode是所有HDFS元數(shù)據(jù)的仲裁者和管理者,這樣,用戶數(shù)據(jù)永遠(yuǎn)不會(huì)流過(guò)Namenode。

    文件系統(tǒng)的名字空間 (namespace)

    HDFS支持傳統(tǒng)的層次型文件組織結(jié)構(gòu)。用戶或者應(yīng)用程序可以創(chuàng)建目錄,然后將文件保存在這些目錄里。文件系統(tǒng)名字空間的層次結(jié)構(gòu)和大多數(shù)現(xiàn)有的文件系統(tǒng) 類似:用戶可以創(chuàng)建、刪除、移動(dòng)或重命名文件。當(dāng)前,HDFS不支持用戶磁盤配額和訪問(wèn)權(quán)限控制,也不支持硬鏈接和軟鏈接。但是HDFS架構(gòu)并不妨礙實(shí)現(xiàn) 這些特性。

    Namenode負(fù)責(zé)維護(hù)文件系統(tǒng)的名字空間,任何對(duì)文件系統(tǒng)名字空間或?qū)傩缘男薷亩紝⒈籒amenode記錄下來(lái)。應(yīng)用程序可以設(shè)置HDFS保存的文件的副本數(shù)目。文件副本的數(shù)目稱為文件的副本系數(shù),這個(gè)信息也是由Namenode保存的。

    數(shù)據(jù)復(fù)制

    HDFS被設(shè)計(jì)成能夠在一個(gè)大集群中跨機(jī)器可靠地存儲(chǔ)超大文件。它將每個(gè)文件存儲(chǔ)成一系列的數(shù)據(jù)塊,除了最后一個(gè),所有的數(shù)據(jù)塊都是同樣大小的。為了容 錯(cuò),文件的所有數(shù)據(jù)塊都會(huì)有副本。每個(gè)文件的數(shù)據(jù)塊大小和副本系數(shù)都是可配置的。應(yīng)用程序可以指定某個(gè)文件的副本數(shù)目。副本系數(shù)可以在文件創(chuàng)建的時(shí)候指 定,也可以在之后改變。HDFS中的文件都是一次性寫入的,并且嚴(yán)格要求在任何時(shí)候只能有一個(gè)寫入者。

    Namenode全權(quán)管理數(shù)據(jù)塊的復(fù)制,它周期性地從集群中的每個(gè)Datanode接收心跳信號(hào)和塊狀態(tài)報(bào)告(Blockreport)。接收到心跳信號(hào)意味著該Datanode節(jié)點(diǎn)工作正常。塊狀態(tài)報(bào)告包含了一個(gè)該Datanode上所有數(shù)據(jù)塊的列表。

    HDFS Datanodes

    副本存放: 最最開始的一步

    副本的存放是HDFS可靠性和性能的關(guān)鍵。優(yōu)化的副本存放策略是HDFS區(qū)分于其他大部分分布式文件系統(tǒng)的重要特性。這種特性需要做大量的調(diào)優(yōu),并需要經(jīng) 驗(yàn)的積累。HDFS采用一種稱為機(jī)架感知(rack-aware)的策略來(lái)改進(jìn)數(shù)據(jù)的可靠性、可用性和網(wǎng)絡(luò)帶寬的利用率。目前實(shí)現(xiàn)的副本存放策略只是在這 個(gè)方向上的第一步。實(shí)現(xiàn)這個(gè)策略的短期目標(biāo)是驗(yàn)證它在生產(chǎn)環(huán)境下的有效性,觀察它的行為,為實(shí)現(xiàn)更先進(jìn)的策略打下測(cè)試和研究的基礎(chǔ)。

    大型HDFS實(shí)例一般運(yùn)行在跨越多個(gè)機(jī)架的計(jì)算機(jī)組成的集群上,不同機(jī)架上的兩臺(tái)機(jī)器之間的通訊需要經(jīng)過(guò)交換機(jī)。在大多數(shù)情況下,同一個(gè)機(jī)架內(nèi)的兩臺(tái)機(jī)器間的帶寬會(huì)比不同機(jī)架的兩臺(tái)機(jī)器間的帶寬大。

    通過(guò)一個(gè)機(jī)架感知的 過(guò)程,Namenode可以確定每個(gè)Datanode所屬的機(jī)架id。一個(gè)簡(jiǎn)單但沒(méi)有優(yōu)化的策略就是將副本存放在不同的機(jī)架上。這樣可以有效防止當(dāng)整個(gè)機(jī) 架失效時(shí)數(shù)據(jù)的丟失,并且允許讀數(shù)據(jù)的時(shí)候充分利用多個(gè)機(jī)架的帶寬。這種策略設(shè)置可以將副本均勻分布在集群中,有利于當(dāng)組件失效情況下的負(fù)載均衡。但是, 因?yàn)檫@種策略的一個(gè)寫操作需要傳輸數(shù)據(jù)塊到多個(gè)機(jī)架,這增加了寫的代價(jià)。

    在大多數(shù)情況下,副本系數(shù)是3,HDFS的存放策略是將一個(gè)副本存放在本地機(jī)架的節(jié)點(diǎn)上,一個(gè)副本放在同一機(jī)架的另一個(gè)節(jié)點(diǎn)上,最后一個(gè)副本放在不同機(jī)架 的節(jié)點(diǎn)上。這種策略減少了機(jī)架間的數(shù)據(jù)傳輸,這就提高了寫操作的效率。機(jī)架的錯(cuò)誤遠(yuǎn)遠(yuǎn)比節(jié)點(diǎn)的錯(cuò)誤少,所以這個(gè)策略不會(huì)影響到數(shù)據(jù)的可靠性和可用性。于此 同時(shí),因?yàn)閿?shù)據(jù)塊只放在兩個(gè)(不是三個(gè))不同的機(jī)架上,所以此策略減少了讀取數(shù)據(jù)時(shí)需要的網(wǎng)絡(luò)傳輸總帶寬。在這種策略下,副本并不是均勻分布在不同的機(jī)架 上。三分之一的副本在一個(gè)節(jié)點(diǎn)上,三分之二的副本在一個(gè)機(jī)架上,其他副本均勻分布在剩下的機(jī)架中,這一策略在不損害數(shù)據(jù)可靠性和讀取性能的情況下改進(jìn)了寫 的性能。

    當(dāng)前,這里介紹的默認(rèn)副本存放策略正在開發(fā)的過(guò)程中。

    副本選擇

    為了降低整體的帶寬消耗和讀取延時(shí),HDFS會(huì)盡量讓讀取程序讀取離它最近的副本。如果在讀取程序的同一個(gè)機(jī)架上有一個(gè)副本,那么就讀取該副本。如果一個(gè)HDFS集群跨越多個(gè)數(shù)據(jù)中心,那么客戶端也將首先讀本地?cái)?shù)據(jù)中心的副本。

    安全模式

    Namenode啟動(dòng)后會(huì)進(jìn)入一個(gè)稱為安全模式的特殊狀態(tài)。處于安全模式的Namenode是不會(huì)進(jìn)行數(shù)據(jù)塊的復(fù)制的。Namenode從所有的 Datanode接收心跳信號(hào)和塊狀態(tài)報(bào)告。塊狀態(tài)報(bào)告包括了某個(gè)Datanode所有的數(shù)據(jù)塊列表。每個(gè)數(shù)據(jù)塊都有一個(gè)指定的最小副本數(shù)。當(dāng) Namenode檢測(cè)確認(rèn)某個(gè)數(shù)據(jù)塊的副本數(shù)目達(dá)到這個(gè)最小值,那么該數(shù)據(jù)塊就會(huì)被認(rèn)為是副本安全(safely replicated)的;在一定百分比(這個(gè)參數(shù)可配置)的數(shù)據(jù)塊被Namenode檢測(cè)確認(rèn)是安全之后(加上一個(gè)額外的30秒等待時(shí) 間),Namenode將退出安全模式狀態(tài)。接下來(lái)它會(huì)確定還有哪些數(shù)據(jù)塊的副本沒(méi)有達(dá)到指定數(shù)目,并將這些數(shù)據(jù)塊復(fù)制到其他Datanode上。

    文件系統(tǒng)元數(shù)據(jù)的持久化

    Namenode上保存著HDFS的名字空間。對(duì)于任何對(duì)文件系統(tǒng)元數(shù)據(jù)產(chǎn)生修改的操作,Namenode都會(huì)使用一種稱為EditLog的事務(wù)日志記錄 下來(lái)。例如,在HDFS中創(chuàng)建一個(gè)文件,Namenode就會(huì)在Editlog中插入一條記錄來(lái)表示;同樣地,修改文件的副本系數(shù)也將往Editlog插 入一條記錄。Namenode在本地操作系統(tǒng)的文件系統(tǒng)中存儲(chǔ)這個(gè)Editlog。整個(gè)文件系統(tǒng)的名字空間,包括數(shù)據(jù)塊到文件的映射、文件的屬性等,都存 儲(chǔ)在一個(gè)稱為FsImage的文件中,這個(gè)文件也是放在Namenode所在的本地文件系統(tǒng)上。

    Namenode在內(nèi)存中保存著整個(gè)文件系統(tǒng)的名字空間和文件數(shù)據(jù)塊映射(Blockmap)的映像。這個(gè)關(guān)鍵的元數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)得很緊湊,因而一個(gè)有4G 內(nèi)存的Namenode足夠支撐大量的文件和目錄。當(dāng)Namenode啟動(dòng)時(shí),它從硬盤中讀取Editlog和FsImage,將所有Editlog中的 事務(wù)作用在內(nèi)存中的FsImage上,并將這個(gè)新版本的FsImage從內(nèi)存中保存到本地磁盤上,然后刪除舊的Editlog,因?yàn)檫@個(gè)舊的 Editlog的事務(wù)都已經(jīng)作用在FsImage上了。這個(gè)過(guò)程稱為一個(gè)檢查點(diǎn)(checkpoint)。在當(dāng)前實(shí)現(xiàn)中,檢查點(diǎn)只發(fā)生在Namenode 啟動(dòng)時(shí),在不久的將來(lái)將實(shí)現(xiàn)支持周期性的檢查點(diǎn)。

    Datanode將HDFS數(shù)據(jù)以文件的形式存儲(chǔ)在本地的文件系統(tǒng)中,它并不知道有關(guān)HDFS文件的信息。它把每個(gè)HDFS數(shù)據(jù)塊存儲(chǔ)在本地文件系統(tǒng)的一 個(gè)單獨(dú)的文件中。Datanode并不在同一個(gè)目錄創(chuàng)建所有的文件,實(shí)際上,它用試探的方法來(lái)確定每個(gè)目錄的最佳文件數(shù)目,并且在適當(dāng)?shù)臅r(shí)候創(chuàng)建子目錄。 在同一個(gè)目錄中創(chuàng)建所有的本地文件并不是最優(yōu)的選擇,這是因?yàn)楸镜匚募到y(tǒng)可能無(wú)法高效地在單個(gè)目錄中支持大量的文件。當(dāng)一個(gè)Datanode啟動(dòng)時(shí),它 會(huì)掃描本地文件系統(tǒng),產(chǎn)生一個(gè)這些本地文件對(duì)應(yīng)的所有HDFS數(shù)據(jù)塊的列表,然后作為報(bào)告發(fā)送到Namenode,這個(gè)報(bào)告就是塊狀態(tài)報(bào)告。

    通訊協(xié)議

    所有的HDFS通訊協(xié)議都是建立在TCP/IP協(xié)議之上。客戶端通過(guò)一個(gè)可配置的TCP端口連接到Namenode,通過(guò)ClientProtocol協(xié)議與Namenode交互。而Datanode使用DatanodeProtocol協(xié)議與Namenode交互。一個(gè)遠(yuǎn)程過(guò)程調(diào)用(RPC)模型被抽象出來(lái)封裝ClientProtocol和Datanodeprotocol協(xié)議。在設(shè)計(jì)上,Namenode不會(huì)主動(dòng)發(fā)起RPC,而是響應(yīng)來(lái)自客戶端或 Datanode 的RPC請(qǐng)求。

    健壯性

    HDFS的主要目標(biāo)就是即使在出錯(cuò)的情況下也要保證數(shù)據(jù)存儲(chǔ)的可靠性。常見的三種出錯(cuò)情況是:Namenode出錯(cuò), Datanode出錯(cuò)和網(wǎng)絡(luò)割裂(network partitions)。

    磁盤數(shù)據(jù)錯(cuò)誤,心跳檢測(cè)和重新復(fù)制

    每個(gè)Datanode節(jié)點(diǎn)周期性地向Namenode發(fā)送心跳信號(hào)。網(wǎng)絡(luò)割裂可能導(dǎo)致一部分Datanode跟Namenode失去聯(lián)系。 Namenode通過(guò)心跳信號(hào)的缺失來(lái)檢測(cè)這一情況,并將這些近期不再發(fā)送心跳信號(hào)Datanode標(biāo)記為宕機(jī),不會(huì)再將新的IO請(qǐng) 求發(fā)給它們。任何存儲(chǔ)在宕機(jī)Datanode上的數(shù)據(jù)將不再有效。Datanode的宕機(jī)可能會(huì)引起一些數(shù)據(jù)塊的副本系數(shù)低于指定值,Namenode不 斷地檢測(cè)這些需要復(fù)制的數(shù)據(jù)塊,一旦發(fā)現(xiàn)就啟動(dòng)復(fù)制操作。在下列情況下,可能需要重新復(fù)制:某個(gè)Datanode節(jié)點(diǎn)失效,某個(gè)副本遭到損 壞,Datanode上的硬盤錯(cuò)誤,或者文件的副本系數(shù)增大。

    集群均衡

    HDFS的架構(gòu)支持?jǐn)?shù)據(jù)均衡策略。如果某個(gè)Datanode節(jié)點(diǎn)上的空閑空間低于特定的臨界點(diǎn),按照均衡策略系統(tǒng)就會(huì)自動(dòng)地將數(shù)據(jù)從這個(gè)Datanode 移動(dòng)到其他空閑的Datanode。當(dāng)對(duì)某個(gè)文件的請(qǐng)求突然增加,那么也可能啟動(dòng)一個(gè)計(jì)劃創(chuàng)建該文件新的副本,并且同時(shí)重新平衡集群中的其他數(shù)據(jù)。這些均 衡策略目前還沒(méi)有實(shí)現(xiàn)。

    數(shù)據(jù)完整性

    從某個(gè)Datanode獲取的數(shù)據(jù)塊有可能是損壞的,損壞可能是由Datanode的存儲(chǔ)設(shè)備錯(cuò)誤、網(wǎng)絡(luò)錯(cuò)誤或者軟件bug造成的。HDFS客戶端軟件實(shí) 現(xiàn)了對(duì)HDFS文件內(nèi)容的校驗(yàn)和(checksum)檢查。當(dāng)客戶端創(chuàng)建一個(gè)新的HDFS文件,會(huì)計(jì)算這個(gè)文件每個(gè)數(shù)據(jù)塊的校驗(yàn)和,并將校驗(yàn)和作為一個(gè)單 獨(dú)的隱藏文件保存在同一個(gè)HDFS名字空間下。當(dāng)客戶端獲取文件內(nèi)容后,它會(huì)檢驗(yàn)從Datanode獲取的數(shù)據(jù)跟相應(yīng)的校驗(yàn)和文件中的校驗(yàn)和是否匹配,如 果不匹配,客戶端可以選擇從其他Datanode獲取該數(shù)據(jù)塊的副本。

    元數(shù)據(jù)磁盤錯(cuò)誤

    FsImage和Editlog是HDFS的核心數(shù)據(jù)結(jié)構(gòu)。如果這些文件損壞了,整個(gè)HDFS實(shí)例都將失效。因而,Namenode可以配置成支持維護(hù)多 個(gè)FsImage和Editlog的副本。任何對(duì)FsImage或者Editlog的修改,都將同步到它們的副本上。這種多副本的同步操作可能會(huì)降低 Namenode每秒處理的名字空間事務(wù)數(shù)量。然而這個(gè)代價(jià)是可以接受的,因?yàn)榧词笻DFS的應(yīng)用是數(shù)據(jù)密集的,它們也非元數(shù)據(jù)密集的。當(dāng) Namenode重啟的時(shí)候,它會(huì)選取最近的完整的FsImage和Editlog來(lái)使用。

    Namenode是HDFS集群中的單點(diǎn)故障(single point of failure)所在。如果Namenode機(jī)器故障,是需要手工干預(yù)的。目前,自動(dòng)重啟或在另一臺(tái)機(jī)器上做Namenode故障轉(zhuǎn)移的功能還沒(méi)實(shí)現(xiàn)。

    快照

    快照支持某一特定時(shí)刻的數(shù)據(jù)的復(fù)制備份。利用快照,可以讓HDFS在數(shù)據(jù)損壞時(shí)恢復(fù)到過(guò)去一個(gè)已知正確的時(shí)間點(diǎn)。HDFS目前還不支持快照功能,但計(jì)劃在將來(lái)的版本進(jìn)行支持。

    數(shù)據(jù)組織

    數(shù)據(jù)塊

    HDFS被設(shè)計(jì)成支持大文件,適用HDFS的是那些需要處理大規(guī)模的數(shù)據(jù)集的應(yīng)用。這些應(yīng)用都是只寫入數(shù)據(jù)一次,但卻讀取一次或多次,并且讀取速度應(yīng)能滿 足流式讀取的需要。HDFS支持文件的“一次寫入多次讀取”語(yǔ)義。一個(gè)典型的數(shù)據(jù)塊大小是64MB。因而,HDFS中的文件總是按照64M被切分成不同的 塊,每個(gè)塊盡可能地存儲(chǔ)于不同的Datanode中。

    Staging

    客戶端創(chuàng)建文件的請(qǐng)求其實(shí)并沒(méi)有立即發(fā)送給Namenode,事實(shí)上,在剛開始階段HDFS客戶端會(huì)先將文件數(shù)據(jù)緩存到本地的一個(gè)臨時(shí)文件。應(yīng)用程序的寫 操作被透明地重定向到這個(gè)臨時(shí)文件。當(dāng)這個(gè)臨時(shí)文件累積的數(shù)據(jù)量超過(guò)一個(gè)數(shù)據(jù)塊的大小,客戶端才會(huì)聯(lián)系Namenode。Namenode將文件名插入文 件系統(tǒng)的層次結(jié)構(gòu)中,并且分配一個(gè)數(shù)據(jù)塊給它。然后返回Datanode的標(biāo)識(shí)符和目標(biāo)數(shù)據(jù)塊給客戶端。接著客戶端將這塊數(shù)據(jù)從本地臨時(shí)文件上傳到指定的 Datanode上。當(dāng)文件關(guān)閉時(shí),在臨時(shí)文件中剩余的沒(méi)有上傳的數(shù)據(jù)也會(huì)傳輸?shù)街付ǖ腄atanode上。然后客戶端告訴Namenode文件已經(jīng)關(guān) 閉。此時(shí)Namenode才將文件創(chuàng)建操作提交到日志里進(jìn)行存儲(chǔ)。如果Namenode在文件關(guān)閉前宕機(jī)了,則該文件將丟失。

    上述方法是對(duì)在HDFS上運(yùn)行的目標(biāo)應(yīng)用進(jìn)行認(rèn)真考慮后得到的結(jié)果。這些應(yīng)用需要進(jìn)行文件的流式寫入。如果不采用客戶端緩存,由于網(wǎng)絡(luò)速度和網(wǎng)絡(luò)堵塞會(huì)對(duì)吞估量造成比較大的影響。這種方法并不是沒(méi)有先例的,早期的文件系統(tǒng),比如AFS,就用客戶端緩存來(lái)提高性能。為了達(dá)到更高的數(shù)據(jù)上傳效率,已經(jīng)放松了POSIX標(biāo)準(zhǔn)的要求。

    流水線復(fù)制

    當(dāng)客戶端向HDFS文件寫入數(shù)據(jù)的時(shí)候,一開始是寫到本地臨時(shí)文件中。假設(shè)該文件的副本系數(shù)設(shè)置為3,當(dāng)本地臨時(shí)文件累積到一個(gè)數(shù)據(jù)塊的大小時(shí),客戶端會(huì) 從Namenode獲取一個(gè)Datanode列表用于存放副本。然后客戶端開始向第一個(gè)Datanode傳輸數(shù)據(jù),第一個(gè)Datanode一小部分一小部 分(4 KB)地接收數(shù)據(jù),將每一部分寫入本地倉(cāng)庫(kù),并同時(shí)傳輸該部分到列表中第二個(gè)Datanode節(jié)點(diǎn)。第二個(gè)Datanode也是這樣,一小部分一小部分地 接收數(shù)據(jù),寫入本地倉(cāng)庫(kù),并同時(shí)傳給第三個(gè)Datanode。最后,第三個(gè)Datanode接收數(shù)據(jù)并存儲(chǔ)在本地。因此,Datanode能流水線式地從 前一個(gè)節(jié)點(diǎn)接收數(shù)據(jù),并在同時(shí)轉(zhuǎn)發(fā)給下一個(gè)節(jié)點(diǎn),數(shù)據(jù)以流水線的方式從前一個(gè)Datanode復(fù)制到下一個(gè)。

    可訪問(wèn)性

    HDFS給應(yīng)用提供了多種訪問(wèn)方式。用戶可以通過(guò)Java API接口訪問(wèn),也可以通過(guò)C語(yǔ)言的封裝API訪問(wèn),還可以通過(guò)瀏覽器的方式訪問(wèn)HDFS中的文件。通過(guò)WebDAV協(xié)議訪問(wèn)的方式正在開發(fā)中。

    DFSShell

    HDFS以文件和目錄的形式組織用戶數(shù)據(jù)。它提供了一個(gè)命令行的接口(DFSShell)讓用戶與HDFS中的數(shù)據(jù)進(jìn)行交互。命令的語(yǔ)法和用戶熟悉的其他shell(例如 bash, csh)工具類似。下面是一些動(dòng)作/命令的示例:

    動(dòng)作 命令
    創(chuàng)建一個(gè)名為/foodir的目錄 bin/hadoop dfs -mkdir /foodir
    創(chuàng)建一個(gè)名為/foodir的目錄 bin/hadoop dfs -mkdir /foodir
    查看名為/foodir/myfile.txt的文件內(nèi)容 bin/hadoop dfs -cat /foodir/myfile.txt

    DFSShell 可以用在那些通過(guò)腳本語(yǔ)言和文件系統(tǒng)進(jìn)行交互的應(yīng)用程序上。

    DFSAdmin

    DFSAdmin 命令用來(lái)管理HDFS集群。這些命令只有HDSF的管理員才能使用。下面是一些動(dòng)作/命令的示例:

    動(dòng)作 命令
    將集群置于安全模式 bin/hadoop dfsadmin -safemode enter
    顯示Datanode列表 bin/hadoop dfsadmin -report
    使Datanode節(jié)點(diǎn)datanodename退役 bin/hadoop dfsadmin -decommission datanodename

    瀏覽器接口

    一個(gè)典型的HDFS安裝會(huì)在一個(gè)可配置的TCP端口開啟一個(gè)Web服務(wù)器用于暴露HDFS的名字空間。用戶可以用瀏覽器來(lái)瀏覽HDFS的名字空間和查看文件的內(nèi)容。

    存儲(chǔ)空間回收

    文件的刪除和恢復(fù)

    當(dāng)用戶或應(yīng)用程序刪除某個(gè)文件時(shí),這個(gè)文件并沒(méi)有立刻從HDFS中刪除。實(shí)際上,HDFS會(huì)將這個(gè)文件重命名轉(zhuǎn)移到/trash目錄。只要文件還在/trash目錄中,該文件就可以被迅速地恢復(fù)。文件在/trash中保存的時(shí)間是可配置的,當(dāng)超過(guò)這個(gè)時(shí)間時(shí),Namenode就會(huì)將該文件從名字空間中刪除。刪除文件會(huì)使得該文件相關(guān)的數(shù)據(jù)塊被釋放。注意,從用戶刪除文件到HDFS空閑空間的增加之間會(huì)有一定時(shí)間的延遲。

    只要被刪除的文件還在/trash目錄中,用戶就可以恢復(fù)這個(gè)文件。如果用戶想恢復(fù)被刪除的文件,他/她可以瀏覽/trash目錄找回該文件。/trash目錄僅僅保存被刪除文件的最后副本。/trash目錄與其他的目錄沒(méi)有什么區(qū)別,除了一點(diǎn):在該目錄上HDFS會(huì)應(yīng)用一個(gè)特殊策略來(lái)自動(dòng)刪除文件。目前的默認(rèn)策略是刪除/trash中保留時(shí)間超過(guò)6小時(shí)的文件。將來(lái),這個(gè)策略可以通過(guò)一個(gè)被良好定義的接口配置。

    減少副本系數(shù)

    當(dāng)一個(gè)文件的副本系數(shù)被減小后,Namenode會(huì)選擇過(guò)剩的副本刪除。下次心跳檢測(cè)時(shí)會(huì)將該信息傳遞給Datanode。Datanode遂即移除相應(yīng)的數(shù)據(jù)塊,集群中的空閑空間加大。同樣,在調(diào)用setReplicationAPI結(jié)束和集群中空閑空間增加間會(huì)有一定的延遲。

    參考資料

    posted @ 2011-08-24 12:59 jadmin 閱讀(129) | 評(píng)論 (0)編輯 收藏

    function is_email($email) {
    ?? ??? ?$exp = "^[a-z'0-9]+([._-][a-z'0-9]+)*@([a-z0-9]+([._-][a-z0-9]+))+$";
    ?? ??? ?if(eregi($exp,$email)) {
    ?? ??? ??? ?return true;
    ?? ??? ?}
    ?? ??? ?return false;
    ?}


    posted @ 2011-08-22 19:37 jadmin 閱讀(99) | 評(píng)論 (0)編輯 收藏

    function remove_quote(&$str) {
    ?? ??? ?if (preg_match("/^\"/",$str)){
    ?? ??? ??? ?$str = substr($str, 1, strlen($str) - 1);
    ?? ??? ?}
    ?? ??? ?//判斷字符串是否以'"'結(jié)束
    ?? ??? ?if (preg_match("/\"$/",$str)){
    ?? ??? ??? ?$str = substr($str, 0, strlen($str) - 1);;
    ?? ??? ?}
    ?? ??? ?return $str;
    ? }

    posted @ 2011-08-22 19:36 jadmin 閱讀(424) | 評(píng)論 (0)編輯 收藏

    function is_chinese($s){
    ??????? $allen = preg_match("/^[^\x80-\xff]+$/", $s);?? //判斷是否是英文
    ??????? $allcn = preg_match("/^[".chr(0xa1)."-".chr(0xff)."]+$/",$s);? //判斷是否是中文
    ??????? if($allen){ ?
    ????????????? return 'allen'; ?
    ??????? }else{ ?
    ????????????? if($allcn){ ?
    ?????????????????? return 'allcn'; ?
    ????????????? }else{ ?
    ?????????????????? return 'encn'; ?
    ????????????? } ?
    ??????? }?
    ?? }

    posted @ 2011-08-22 10:14 jadmin 閱讀(218) | 評(píng)論 (0)編輯 收藏

    DML(data manipulation language):
    ?????? 它們是SELECT、UPDATE、INSERT、DELETE,就象它的名字一樣,這4條命令是用來(lái)對(duì)數(shù)據(jù)庫(kù)里的數(shù)據(jù)進(jìn)行操作的語(yǔ)言
    DDL(data definition language):
    ?????? DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定義或改變表(TABLE)的結(jié)構(gòu),數(shù)據(jù)類型,表之間的鏈接和約束等初始化工作上,他們大多在建立表時(shí)使用
    DCL(Data Control Language):
    ?????? 是數(shù)據(jù)庫(kù)控制功能。是用來(lái)設(shè)置或更改數(shù)據(jù)庫(kù)用戶或角色權(quán)限的語(yǔ)句,包括(grant,deny,revoke等)語(yǔ)句。在默認(rèn)狀態(tài)下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人員才有權(quán)力執(zhí)行DCL

    詳細(xì)解釋:
    一、DDL is Data Definition Language statements. Some examples:數(shù)據(jù)定義語(yǔ)言,用于定義和管理 SQL 數(shù)據(jù)庫(kù)中的所有對(duì)象的語(yǔ)言
    ????? 1.CREATE - to create objects in the database?? 創(chuàng)建
    ????? 2.ALTER - alters the structure of the database?? 修改
    ????? 3.DROP - delete objects from the database?? 刪除
    ????? 4.TRUNCATE - remove all records from a table, including all spaces allocated for the records are removed
    ????? TRUNCATE TABLE [Table Name]。
      下面是對(duì)Truncate語(yǔ)句在MSSQLServer2000中用法和原理的說(shuō)明:
      Truncate table 表名 速度快,而且效率高,因?yàn)?
      TRUNCATE TABLE 在功能上與不帶 WHERE 子句的 DELETE 語(yǔ)句相同:二者均刪除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系統(tǒng)和事務(wù)日志資源少。
      DELETE 語(yǔ)句每次刪除一行,并在事務(wù)日志中為所刪除的每行記錄一項(xiàng)。TRUNCATE TABLE 通過(guò)釋放存儲(chǔ)表數(shù)據(jù)所用的數(shù)據(jù)頁(yè)來(lái)刪除數(shù)據(jù),并且只在事務(wù)日志中記錄頁(yè)的釋放。
      TRUNCATE TABLE 刪除表中的所有行,但表結(jié)構(gòu)及其列、約束、索引等保持不變。新行標(biāo)識(shí)所用的計(jì)數(shù)值重置為該列的種子。如果想保留標(biāo)識(shí)計(jì)數(shù)值,請(qǐng)改用 DELETE。如果要?jiǎng)h除表定義及其數(shù)據(jù),請(qǐng)使用 DROP TABLE 語(yǔ)句。
      對(duì)于由 FOREIGN KEY 約束引用的表,不能使用 TRUNCATE TABLE,而應(yīng)使用不帶 WHERE 子句的 DELETE 語(yǔ)句。由于 TRUNCATE TABLE 不記錄在日志中,所以它不能激活觸發(fā)器。
      TRUNCATE TABLE 不能用于參與了索引視圖的表。
    ?????? 5.COMMENT - add comments to the data dictionary 注釋
    ?????? 6.GRANT - gives user's access privileges to database 授權(quán)
    ?????? 7.REVOKE - withdraw access privileges given with the GRANT command?? 收回已經(jīng)授予的權(quán)限

    二、DML is Data Manipulation Language statements. Some examples:數(shù)據(jù)操作語(yǔ)言,SQL中處理數(shù)據(jù)等操作統(tǒng)稱為數(shù)據(jù)操縱語(yǔ)言
    ?????? 1.SELECT - retrieve data from the a database?????????? 查詢
    ?????? 2.INSERT - insert data into a table??????????????????? 添加
    ?????? 3.UPDATE - updates existing data within a table??? 更新
    ?????? 4.DELETE - deletes all records from a table, the space for the records remain?? 刪除
    ?????? 5.CALL - call a PL/SQL or Java subprogram
    ?????? 6.EXPLAIN PLAN - explain access path to data
    ?????? Oracle RDBMS執(zhí)行每一條SQL語(yǔ)句,都必須經(jīng)過(guò)Oracle優(yōu)化器的評(píng)估。所以,了解優(yōu)化器是如何選擇(搜索)路徑以及索引是如何被使用的,對(duì)優(yōu)化SQL語(yǔ)句有很大的幫助。Explain可以用來(lái)迅速方便地查出對(duì)于給定SQL語(yǔ)句中的查詢數(shù)據(jù)是如何得到的即搜索路徑(我們通常稱為Access Path)。從而使我們選擇最優(yōu)的查詢方式達(dá)到最大的優(yōu)化效果。
    ?????? 7.LOCK TABLE - control concurrency 鎖,用于控制并發(fā)

    三、DCL is Data Control Language statements. Some examples:數(shù)據(jù)控制語(yǔ)言,用來(lái)授予或回收訪問(wèn)數(shù)據(jù)庫(kù)的某種特權(quán),并控制數(shù)據(jù)庫(kù)操縱事務(wù)發(fā)生的時(shí)間及效果,對(duì)數(shù)據(jù)庫(kù)實(shí)行監(jiān)視等
    ?????? 1.COMMIT - save work done 提交
    ?????? 2.SAVEPOINT - identify a point in a transaction to which you can later roll back 保存點(diǎn)
    ?????? 3.ROLLBACK - restore database to original since the last COMMIT?? 回滾
    ?????? 4.SET TRANSACTION - Change transaction options like what rollback segment to use?? 設(shè)置當(dāng)前事務(wù)的特性,它對(duì)后面的事務(wù)沒(méi)有影響.


    posted @ 2011-08-17 19:40 jadmin 閱讀(109) | 評(píng)論 (0)編輯 收藏
    主站蜘蛛池模板: 久久狠狠爱亚洲综合影院| 亚洲色中文字幕无码AV| 最近免费中文字幕大全视频| 在线看片免费人成视久网| 久久精品免费视频观看| 免费在线中文日本| 精品免费tv久久久久久久| 日本高清免费观看| 久久精品国产大片免费观看| 免费无码中文字幕A级毛片| 99精品一区二区免费视频| 亚洲香蕉免费有线视频| 91情侣在线精品国产免费| 在线看片无码永久免费视频| 毛片免费在线视频| 黑人粗长大战亚洲女2021国产精品成人免费视频 | 亚洲一区二区三区高清视频| 亚洲av永久无码精品三区在线4| 亚洲国产福利精品一区二区| 亚洲av无码电影网| 亚洲Av无码国产一区二区| 在线亚洲精品视频| 插鸡网站在线播放免费观看| 毛片免费在线观看| 2021精品国产品免费观看| 国产福利在线观看免费第一福利| 免费中文熟妇在线影片| 国产成人无码区免费A∨视频网站| 亚洲高清成人一区二区三区| 久久久久亚洲精品无码网址 | 亚洲精品视频免费观看| 亚洲爆乳无码专区| 亚洲喷奶水中文字幕电影| 亚洲中文字幕久久久一区| 特黄aa级毛片免费视频播放| 99久久成人国产精品免费| 18级成人毛片免费观看| 午夜视频免费成人| 国产亚洲美女精品久久久2020| 亚洲一区精品中文字幕| 亚洲日韩AV一区二区三区四区|