posts - 495,  comments - 11,  trackbacks - 0
            2011年6月9日

          > 引言
            在Jorm中,主鍵的生成策略主要有AUTO、UUID、GUID、FOREIGN、SEQUENCE、INCREMENT、IDENTITY、ASSIGNED,下面分別來講述這幾種策略的應用場景

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

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

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

          > GenerationType.UUID
            與數據庫無關的策略,適用數據類型:字符串類型,適用所有數據庫,長度須大于或等于32
            @Id(GenerationType.UUID)
            private String id;

          > GenerationType.GUID
            與UUID有點類似,不過這個id值是又數據庫來生成的,適用于數據庫MySQL、PostgreSQL、SQL Server、Oracle等
            @Id(GenerationType.GUID)
            private String id;

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

          > GenerationType.SEQUENCE
            這個不用多說,應用于Oracle、H2、PostgreSQL等有sequence序列功能的數據庫

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

           

          項目地址:http://javaclub.sourceforge.net/jorm.html
          下載地址:http://sourceforge.net/projects/javaclub/files/jorm/


          posted @ 2011-10-10 15:17 jadmin 閱讀(1497) | 評論 (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);// 指定每批處理的記錄數
             
              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();
          }

          項目地址:http://javaclub.sourceforge.net/jorm.html
          下載地址: http://sourceforge.net/projects/javaclub/files/jorm/

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

          ??????在一般情況下,在新增領域對象后,都需要獲取對應的主鍵值。使用應用層來維護主鍵,在一定程度上有利于程序性能的優化和應用移植性的提高。在采用數據庫自增主鍵的方案里,如果JDBC驅動不能綁定新增記錄對應的主鍵,就需要手工執行查詢語句以獲取對應的主鍵值,對于高并發的系統,這很容易返回錯誤的主鍵。通過帶緩存的DataFieldMaxValueIncrementer,可以一次獲取批量的主鍵值,供多次插入領域對象時使用,它的執行性能是很高的。

          ??????我們經常使用數據的自增字段作為表主鍵,也即主鍵值不在應用層產生,而是在新增記錄時,由數據庫產生。這樣,應用層在保存對象前并不知道對象主鍵值,而必須在保存數據后才能從數據庫中返回主鍵值。在很多情況下,我們需要獲取新對象持久化后的主鍵值。在Hibernate等ORM框架,新對象持久化后,Hibernate會自動將主鍵值綁定到對象上,給程序的開發帶來了很多方便。?

          ??????在JDBC 3.0規范中,當新增記錄時,允許將數據庫自動產生的主鍵值綁定到Statement或PreparedStatement中。

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

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

          ??????當autoGeneratedKeys參數設置為Statement.RETURN_GENERATED_KEYS值時即可綁定數據庫產生的主鍵值,設置為Statement.NO_GENERATED_KEYS時,不綁定主鍵值。下面的代碼演示了Statement綁定并獲取數據庫產生的主鍵值的過程:

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

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

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

          ??????當僅插入一行數據,主鍵不是復合鍵且是數字類型時,通過該方法可以直接返回新的主鍵值。如果是復合主鍵,或者有多個主鍵返回時,該方法拋出 InvalidDataAccessApiUsageException。該方法是最常用的方法,因為一般情況下,我們一次僅插入一條數據并且主鍵字段類型為數字類型;?

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

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

          ??????如果返回多個主鍵,即PreparedStatement新增了多條記錄,則每一個主鍵對應一個Map,多個Map構成一個List。

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

          ??????Spring為KeyHolder接口指代了一個通用的實現類GeneratedKeyHolder,該類返回新增記錄時的自增長主鍵值。假設我們希望在新增論壇板塊對象后,希望將主鍵值加載到對象中,則可以按以下代碼進行調整:

          ????? public voidaddForum(final Forum forum) {
          ??????????? final String sql = "INSERT INTO t_forum(forum_name,forum_desc) VALUES(?,?)";
          ??????????? KeyHolder keyHolder = newGeneratedKeyHolder(); // ①創建一個主鍵執有者
          ??????????? 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()); // ②從主鍵執有者中獲取主鍵
          ????? }

          ??????這樣,在調用addForum(Forum forum)新增forum領域對象后,forum將擁有對應的主鍵值,方便后繼的使用。在JDBC 3.0之前的版本中,PreparedStatement不能綁定主鍵,如果采用表自增鍵(如MySQL的auto increment或SQLServer的identity)將給獲取正確的主鍵值帶來挑戰——因為你必須在插入數據后,馬上執行另一條獲取新增主鍵的查詢語句。下面給出了不同數據庫獲取最新自增主鍵值的查詢語句:?

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

          1) Assigned
          主鍵由外部程序負責生成,無需Hibernate參與。


          2) hilo
          通過hi/lo 算法實現的主鍵生成機制,需要額外的數據庫表保存主鍵生成歷史狀態。


          3) seqhilo
          與hilo 類似,通過hi/lo 算法實現的主鍵生成機制,只是主鍵歷史狀態保存在Sequence中,適用于支持Sequence的數據庫,如Oracle。


          4) increment
          主鍵按數值順序遞增。此方式的實現機制為在當前應用實例中維持一個變量,以保存著當前的最大值,之后每次需要生成主鍵的時候將此值加1作為主鍵。 這種方式可能產生的問題是:如果當前有多個實例訪問同一個數據庫,那么由于各個實例各自維護主鍵狀態,不同實例可能生成同樣的主鍵,從而造成主鍵重復異常。因此,如果同一數據庫有多個實例訪問,此方式必須避免使用。


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


          6) sequence
          采用數據庫提供的sequence 機制生成主鍵。如Oralce 中的Sequence。


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


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


          9) uuid.string
          與uuid.hex 類似,只是生成的主鍵未進行編碼(長度16)。在某些數據庫中可能出現問題(如PostgreSQL)。


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


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


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

          ?

          關鍵詞: Hibernate? 主鍵?? 主鍵生成方式? IdentifierGenerator

          ?

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

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

          主要更新:
          ----------------------------------------
           * [35] fix: oracle下一個分頁取limit數錯誤的bug.
           * [34] fix: oracle下檢測是否支持Savepoints時,一個未捕獲的異常.
           * [33] add: 對bonecp的支持
           * [32] add: 對proxool的支持
           * [31] add: 對commons-dbcp的支持
           * [30] fix: classpath沒有config.properties文件會報錯


          posted @ 2011-09-23 10:53 jadmin 閱讀(207) | 評論 (0)編輯 收藏
          > 引言
          有時候我們有這樣的需求,對象有一個屬性可能有多個值,需要在數據庫中作為一個字段存儲

          還是以User為例,career存儲多個職業

          > 建表
          以MySQL為例,執行下面的sql建立數據表
          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;

          > 代碼
          實體類 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);
              }

          }

          > 測試

          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 閱讀(1223) | 評論 (0)編輯 收藏

          > 準備
          以MySQL為例,執行下面的sql建立數據表
          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 (根據實際情況選擇性加入)


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

          jdbc.cfg.xml內容:
          <?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>


          > 實體類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();
              }

          }

          這里數據庫字段和java實體類User的屬性在命名上是一致的,如果不一致,比如如果表創建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;

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

              @Column("user_name")
              private String name;
                  
              // 與數據庫字段命名一致,可以不指定@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();
              }

          }


          > 對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是一個代理對象,因為@Entity(table="t_user", lazy = true)
                  System.out.println(user.getCareer());// 發出查詢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 閱讀(1423) | 評論 (5)編輯 收藏

          > 特點
            1.支持多數據源管理和配置
            2.自動封裝Entity
            3.支持事務
            4.支持存儲過程的方便調用
            5.支持lazy加載
            6.支持分頁查詢
            7.支持多種數據庫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);// 根據主鍵加載

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

            // 分頁查詢
            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);

            // 查詢單個屬性
            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.存儲過程
            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.事務
            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();
            }

          這是一個完全基于JDBC的輕量java orm framework, 目標定位于使用方便,簡單,后續會增加許多新的特性


           

          項目地址:http://javaclub.sourceforge.net/jorm.html

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

           

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

          > 原理

          其實斷點續傳的原理很簡單,就是在 Http 的請求上和一般的下載有所不同而已。
          打個比方,瀏覽器請求服務器上的一個文時,所發出的請求如下:
          假設服務器域名為 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

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

          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

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

          仔細看一下就會發現多了一行 RANGE: bytes=2000070-
          這一行的意思就是告訴服務器 down.zip 這個文件從 2000070 字節開始傳,前面的字節不用傳了。
          服務器收到這個請求以后,返回的信息如下:
          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

          和前面服務器返回的信息比較一下,就會發現增加了一行:
          Content-Range=bytes 2000070-106786027/106786028

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

          > 關鍵點

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

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

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

          從輸入流中取出的字節流就是 down.zip 文件從 2000070 開始的字節流。大家看,其實斷點續傳用 Java 實現起來還是很簡單的吧。接下來要做的事就是怎么保存獲得的流到文件中去了。

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

          }

          ?

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

          SymmetricDS是一個平臺獨立的數據同步和復制的解決方案。

          配置數據模型:

          運行時數據模型:

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

          > 問題:給40億個不重復的unsigned int的整數,沒排過序的,然后再給幾個數,如何快速判斷這幾個數是否在那40億個數當中?

          > 解決:unsigned int 的取值范圍是0到2^32-1。我們可以申請連續的2^32/8=512M的內存,用每一個bit對應一個unsigned int數字。首先將512M內存都初始化為0,然后每處理一個數字就將其對應的bit設置為1。當需要查詢時,直接找到對應bit,看其值是0還是1即可。

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

          lazy的屬性有false、true、extra

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

          extra有個小的智能的地方是,即調用集合的size/contains等方法的時候,hibernate并不會去加載整個集合的數據,而是發出一條聰明的SQL語句,以便獲得需要的值,只有在真正需要用到這些集合元素對象數據的時候,才去發出查詢語句加載所有對象的數據


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

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

          從map reduce計算的角度講,linux作為master節點,linux02和linux03作為slave節點。
          從hdfs數據存儲角度講,linux作為namenode節點,linux02和linux03作為datanode節點。


          一臺namenode機,主機名為linux,hosts文件內容如下:
          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

          兩臺datanode機,主機名為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目錄下

          > 進入root目錄,先后執行命令
          chmod 755 jdk-6u18-linux-i586-rpm.bin
          ./jdk-6u18-linux-i586-rpm.bin

          一路按提示下去就會安裝成功

          > 配置環境變量
          cd進入/etc目錄,vi編輯profile文件,將下面的內容追加到文件末尾
          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

          注意:三臺機器都要安裝JDK~

          2.設置Master/Slave機器之間可以通過SSH無密鑰互相訪問
          最好三臺機器的使用相同的賬戶名,我是直接使用的root賬戶

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

          接下來,需要進入/root/.ssh目錄,執行如下命令:
          cd .ssh

          再把is_rsa.pub文件復制到linux02和linux03機器上去。
          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機linux02:
          以用戶root登錄linux02,在目錄下執行命令:
          ssh-keygen -t rsa
          一路回車下去即可在目錄/root/.ssh/下建立兩個文件 id_rsa.pub和id_rsa。

          接下來,需要進入/root/.ssh目錄,執行如下命令:
          cd .ssh

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

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

          接下來,需要進入/root/.ssh目錄,執行如下命令:
          cd .ssh

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

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

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

          接下來還要完成如下步驟:

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

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

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

          通過上述配置,現在以用戶root登錄linux機,既可以無密鑰認證方式訪問linux02和linux03了,同樣也可以在linux02和linux03上以ssh linux方式連接到linux上進行訪問了。

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

          編輯/etc/profile文件,在文件尾部追加如下內容:
          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的簡單配置已經完成

          > 將在namenode機器上配置好的hadoop部署到datanode機器上
          這里使用scp命令進行遠程傳輸,先后執行命令
          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.測試
          以root用戶登入namenode機linux,進入目錄/usr/hadoop/hadoop-0.20.2/
          cd /usr/hadoop/hadoop-0.20.2

          > 執行格式化
          [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
          ************************************************************/

          > 啟動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命令查看進程
          [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 閱讀(130) | 評論 (0)編輯 收藏

          引言

          Hadoop分布式文件系統(HDFS)被設計成適 合運行在通用硬件(commodity hardware)上的分布式文件系統。它和現有的分布式文件系統有很多共同點。但同時,它和其他的分布式文件系統的區別也是很明顯的。HDFS是一個高 度容錯性的系統,適合部署在廉價的機器上。HDFS能提供高吞吐量的數據訪問,非常適合大規模數據集上的應用。HDFS放寬了一部分POSIX約束,來實 現流式讀取文件系統數據的目的。HDFS在最開始是作為Apache Nutch搜索引擎項目的基礎架構而開發的。HDFS是Apache Hadoop Core項目的一部分。這個項目的地址是http://hadoop.apache.org/core/。

          前提和設計目標

          硬件錯誤

          硬件錯誤是常態而不是異常。HDFS可能由成百上千的服務器所構成,每個服務器上存儲著文件系統的部分數據。我們面對的現實是構成系統的組件數目是巨大 的,而且任一組件都有可能失效,這意味著總是有一部分HDFS的組件是不工作的。因此錯誤檢測和快速、自動的恢復是HDFS最核心的架構目標。

          流式數據訪問

          運行在HDFS上的應用和普通的應用不同,需要流式訪問它們的數據集。HDFS的設計中更多的考慮到了數據批處理,而不是用戶交互處理。比之數據訪問的低 延遲問題,更關鍵的在于數據訪問的高吞吐量。POSIX標準設置的很多硬性約束對HDFS應用系統不是必需的。為了提高數據的吞吐量,在一些關鍵方面對 POSIX的語義做了一些修改。

          大規模數據集

          運行在HDFS上的應用具有很大的數據集。HDFS上的一個典型文件大小一般都在G字節至T字節。因此,HDFS被調節以支持大文件存儲。它應該能提供整 體上高的數據傳輸帶寬,能在一個集群里擴展到數百個節點。一個單一的HDFS實例應該能支撐數以千萬計的文件。

          簡單的一致性模型

          HDFS應用需要一個“一次寫入多次讀取”的文件訪問模型。一個文件經過創建、寫入和關閉之后就不需要改變。這一假設簡化了數據一致性問題,并且使高吞吐 量的數據訪問成為可能。Map/Reduce應用或者網絡爬蟲應用都非常適合這個模型。目前還有計劃在將來擴充這個模型,使之支持文件的附加寫操作。

          “移動計算比移動數據更劃算”

          一個應用請求的計算,離它操作的數據越近就越高效,在數據達到海量級別的時候更是如此。因為這樣就能降低網絡阻塞的影響,提高系統數據的吞吐量。將計算移 動到數據附近,比之將數據移動到應用所在顯然更好。HDFS為應用提供了將它們自己移動到數據附近的接口。

          異構軟硬件平臺間的可移植性

          HDFS在設計的時候就考慮到平臺的可移植性。這種特性方便了HDFS作為大規模數據應用平臺的推廣。

          Namenode 和 Datanode

          HDFS采用master/slave架構。一個HDFS集群是由一個Namenode和一定數目的Datanodes組成。Namenode是一個中心 服務器,負責管理文件系統的名字空間(namespace)以及客戶端對文件的訪問。集群中的Datanode一般是一個節點一個,負責管理它所在節點上 的存儲。HDFS暴露了文件系統的名字空間,用戶能夠以文件的形式在上面存儲數據。從內部看,一個文件其實被分成一個或多個數據塊,這些塊存儲在一組 Datanode上。Namenode執行文件系統的名字空間操作,比如打開、關閉、重命名文件或目錄。它也負責確定數據塊到具體Datanode節點的 映射。Datanode負責處理文件系統客戶端的讀寫請求。在Namenode的統一調度下進行數據塊的創建、刪除和復制。

          HDFS 架構

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

          集群中單一Namenode的結構大大簡化了系統的架構。Namenode是所有HDFS元數據的仲裁者和管理者,這樣,用戶數據永遠不會流過Namenode。

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

          HDFS支持傳統的層次型文件組織結構。用戶或者應用程序可以創建目錄,然后將文件保存在這些目錄里。文件系統名字空間的層次結構和大多數現有的文件系統 類似:用戶可以創建、刪除、移動或重命名文件。當前,HDFS不支持用戶磁盤配額和訪問權限控制,也不支持硬鏈接和軟鏈接。但是HDFS架構并不妨礙實現 這些特性。

          Namenode負責維護文件系統的名字空間,任何對文件系統名字空間或屬性的修改都將被Namenode記錄下來。應用程序可以設置HDFS保存的文件的副本數目。文件副本的數目稱為文件的副本系數,這個信息也是由Namenode保存的。

          數據復制

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

          Namenode全權管理數據塊的復制,它周期性地從集群中的每個Datanode接收心跳信號和塊狀態報告(Blockreport)。接收到心跳信號意味著該Datanode節點工作正常。塊狀態報告包含了一個該Datanode上所有數據塊的列表。

          HDFS Datanodes

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

          副本的存放是HDFS可靠性和性能的關鍵。優化的副本存放策略是HDFS區分于其他大部分分布式文件系統的重要特性。這種特性需要做大量的調優,并需要經 驗的積累。HDFS采用一種稱為機架感知(rack-aware)的策略來改進數據的可靠性、可用性和網絡帶寬的利用率。目前實現的副本存放策略只是在這 個方向上的第一步。實現這個策略的短期目標是驗證它在生產環境下的有效性,觀察它的行為,為實現更先進的策略打下測試和研究的基礎。

          大型HDFS實例一般運行在跨越多個機架的計算機組成的集群上,不同機架上的兩臺機器之間的通訊需要經過交換機。在大多數情況下,同一個機架內的兩臺機器間的帶寬會比不同機架的兩臺機器間的帶寬大。

          通過一個機架感知的 過程,Namenode可以確定每個Datanode所屬的機架id。一個簡單但沒有優化的策略就是將副本存放在不同的機架上。這樣可以有效防止當整個機 架失效時數據的丟失,并且允許讀數據的時候充分利用多個機架的帶寬。這種策略設置可以將副本均勻分布在集群中,有利于當組件失效情況下的負載均衡。但是, 因為這種策略的一個寫操作需要傳輸數據塊到多個機架,這增加了寫的代價。

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

          當前,這里介紹的默認副本存放策略正在開發的過程中。

          副本選擇

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

          安全模式

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

          文件系統元數據的持久化

          Namenode上保存著HDFS的名字空間。對于任何對文件系統元數據產生修改的操作,Namenode都會使用一種稱為EditLog的事務日志記錄 下來。例如,在HDFS中創建一個文件,Namenode就會在Editlog中插入一條記錄來表示;同樣地,修改文件的副本系數也將往Editlog插 入一條記錄。Namenode在本地操作系統的文件系統中存儲這個Editlog。整個文件系統的名字空間,包括數據塊到文件的映射、文件的屬性等,都存 儲在一個稱為FsImage的文件中,這個文件也是放在Namenode所在的本地文件系統上。

          Namenode在內存中保存著整個文件系統的名字空間和文件數據塊映射(Blockmap)的映像。這個關鍵的元數據結構設計得很緊湊,因而一個有4G 內存的Namenode足夠支撐大量的文件和目錄。當Namenode啟動時,它從硬盤中讀取Editlog和FsImage,將所有Editlog中的 事務作用在內存中的FsImage上,并將這個新版本的FsImage從內存中保存到本地磁盤上,然后刪除舊的Editlog,因為這個舊的 Editlog的事務都已經作用在FsImage上了。這個過程稱為一個檢查點(checkpoint)。在當前實現中,檢查點只發生在Namenode 啟動時,在不久的將來將實現支持周期性的檢查點。

          Datanode將HDFS數據以文件的形式存儲在本地的文件系統中,它并不知道有關HDFS文件的信息。它把每個HDFS數據塊存儲在本地文件系統的一 個單獨的文件中。Datanode并不在同一個目錄創建所有的文件,實際上,它用試探的方法來確定每個目錄的最佳文件數目,并且在適當的時候創建子目錄。 在同一個目錄中創建所有的本地文件并不是最優的選擇,這是因為本地文件系統可能無法高效地在單個目錄中支持大量的文件。當一個Datanode啟動時,它 會掃描本地文件系統,產生一個這些本地文件對應的所有HDFS數據塊的列表,然后作為報告發送到Namenode,這個報告就是塊狀態報告。

          通訊協議

          所有的HDFS通訊協議都是建立在TCP/IP協議之上??蛻舳送ㄟ^一個可配置的TCP端口連接到Namenode,通過ClientProtocol協議與Namenode交互。而Datanode使用DatanodeProtocol協議與Namenode交互。一個遠程過程調用(RPC)模型被抽象出來封裝ClientProtocol和Datanodeprotocol協議。在設計上,Namenode不會主動發起RPC,而是響應來自客戶端或 Datanode 的RPC請求。

          健壯性

          HDFS的主要目標就是即使在出錯的情況下也要保證數據存儲的可靠性。常見的三種出錯情況是:Namenode出錯, Datanode出錯和網絡割裂(network partitions)。

          磁盤數據錯誤,心跳檢測和重新復制

          每個Datanode節點周期性地向Namenode發送心跳信號。網絡割裂可能導致一部分Datanode跟Namenode失去聯系。 Namenode通過心跳信號的缺失來檢測這一情況,并將這些近期不再發送心跳信號Datanode標記為宕機,不會再將新的IO請 求發給它們。任何存儲在宕機Datanode上的數據將不再有效。Datanode的宕機可能會引起一些數據塊的副本系數低于指定值,Namenode不 斷地檢測這些需要復制的數據塊,一旦發現就啟動復制操作。在下列情況下,可能需要重新復制:某個Datanode節點失效,某個副本遭到損 壞,Datanode上的硬盤錯誤,或者文件的副本系數增大。

          集群均衡

          HDFS的架構支持數據均衡策略。如果某個Datanode節點上的空閑空間低于特定的臨界點,按照均衡策略系統就會自動地將數據從這個Datanode 移動到其他空閑的Datanode。當對某個文件的請求突然增加,那么也可能啟動一個計劃創建該文件新的副本,并且同時重新平衡集群中的其他數據。這些均 衡策略目前還沒有實現。

          數據完整性

          從某個Datanode獲取的數據塊有可能是損壞的,損壞可能是由Datanode的存儲設備錯誤、網絡錯誤或者軟件bug造成的。HDFS客戶端軟件實 現了對HDFS文件內容的校驗和(checksum)檢查。當客戶端創建一個新的HDFS文件,會計算這個文件每個數據塊的校驗和,并將校驗和作為一個單 獨的隱藏文件保存在同一個HDFS名字空間下。當客戶端獲取文件內容后,它會檢驗從Datanode獲取的數據跟相應的校驗和文件中的校驗和是否匹配,如 果不匹配,客戶端可以選擇從其他Datanode獲取該數據塊的副本。

          元數據磁盤錯誤

          FsImage和Editlog是HDFS的核心數據結構。如果這些文件損壞了,整個HDFS實例都將失效。因而,Namenode可以配置成支持維護多 個FsImage和Editlog的副本。任何對FsImage或者Editlog的修改,都將同步到它們的副本上。這種多副本的同步操作可能會降低 Namenode每秒處理的名字空間事務數量。然而這個代價是可以接受的,因為即使HDFS的應用是數據密集的,它們也非元數據密集的。當 Namenode重啟的時候,它會選取最近的完整的FsImage和Editlog來使用。

          Namenode是HDFS集群中的單點故障(single point of failure)所在。如果Namenode機器故障,是需要手工干預的。目前,自動重啟或在另一臺機器上做Namenode故障轉移的功能還沒實現。

          快照

          快照支持某一特定時刻的數據的復制備份。利用快照,可以讓HDFS在數據損壞時恢復到過去一個已知正確的時間點。HDFS目前還不支持快照功能,但計劃在將來的版本進行支持。

          數據組織

          數據塊

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

          Staging

          客戶端創建文件的請求其實并沒有立即發送給Namenode,事實上,在剛開始階段HDFS客戶端會先將文件數據緩存到本地的一個臨時文件。應用程序的寫 操作被透明地重定向到這個臨時文件。當這個臨時文件累積的數據量超過一個數據塊的大小,客戶端才會聯系Namenode。Namenode將文件名插入文 件系統的層次結構中,并且分配一個數據塊給它。然后返回Datanode的標識符和目標數據塊給客戶端。接著客戶端將這塊數據從本地臨時文件上傳到指定的 Datanode上。當文件關閉時,在臨時文件中剩余的沒有上傳的數據也會傳輸到指定的Datanode上。然后客戶端告訴Namenode文件已經關 閉。此時Namenode才將文件創建操作提交到日志里進行存儲。如果Namenode在文件關閉前宕機了,則該文件將丟失。

          上述方法是對在HDFS上運行的目標應用進行認真考慮后得到的結果。這些應用需要進行文件的流式寫入。如果不采用客戶端緩存,由于網絡速度和網絡堵塞會對吞估量造成比較大的影響。這種方法并不是沒有先例的,早期的文件系統,比如AFS,就用客戶端緩存來提高性能。為了達到更高的數據上傳效率,已經放松了POSIX標準的要求。

          流水線復制

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

          可訪問性

          HDFS給應用提供了多種訪問方式。用戶可以通過Java API接口訪問,也可以通過C語言的封裝API訪問,還可以通過瀏覽器的方式訪問HDFS中的文件。通過WebDAV協議訪問的方式正在開發中。

          DFSShell

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

          動作 命令
          創建一個名為/foodir的目錄 bin/hadoop dfs -mkdir /foodir
          創建一個名為/foodir的目錄 bin/hadoop dfs -mkdir /foodir
          查看名為/foodir/myfile.txt的文件內容 bin/hadoop dfs -cat /foodir/myfile.txt

          DFSShell 可以用在那些通過腳本語言和文件系統進行交互的應用程序上。

          DFSAdmin

          DFSAdmin 命令用來管理HDFS集群。這些命令只有HDSF的管理員才能使用。下面是一些動作/命令的示例:

          動作 命令
          將集群置于安全模式 bin/hadoop dfsadmin -safemode enter
          顯示Datanode列表 bin/hadoop dfsadmin -report
          使Datanode節點datanodename退役 bin/hadoop dfsadmin -decommission datanodename

          瀏覽器接口

          一個典型的HDFS安裝會在一個可配置的TCP端口開啟一個Web服務器用于暴露HDFS的名字空間。用戶可以用瀏覽器來瀏覽HDFS的名字空間和查看文件的內容。

          存儲空間回收

          文件的刪除和恢復

          當用戶或應用程序刪除某個文件時,這個文件并沒有立刻從HDFS中刪除。實際上,HDFS會將這個文件重命名轉移到/trash目錄。只要文件還在/trash目錄中,該文件就可以被迅速地恢復。文件在/trash中保存的時間是可配置的,當超過這個時間時,Namenode就會將該文件從名字空間中刪除。刪除文件會使得該文件相關的數據塊被釋放。注意,從用戶刪除文件到HDFS空閑空間的增加之間會有一定時間的延遲。

          只要被刪除的文件還在/trash目錄中,用戶就可以恢復這個文件。如果用戶想恢復被刪除的文件,他/她可以瀏覽/trash目錄找回該文件。/trash目錄僅僅保存被刪除文件的最后副本。/trash目錄與其他的目錄沒有什么區別,除了一點:在該目錄上HDFS會應用一個特殊策略來自動刪除文件。目前的默認策略是刪除/trash中保留時間超過6小時的文件。將來,這個策略可以通過一個被良好定義的接口配置。

          減少副本系數

          當一個文件的副本系數被減小后,Namenode會選擇過剩的副本刪除。下次心跳檢測時會將該信息傳遞給Datanode。Datanode遂即移除相應的數據塊,集群中的空閑空間加大。同樣,在調用setReplicationAPI結束和集群中空閑空間增加間會有一定的延遲。

          參考資料

          posted @ 2011-08-24 12:59 jadmin 閱讀(133) | 評論 (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 閱讀(102) | 評論 (0)編輯 收藏

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

          posted @ 2011-08-22 19:36 jadmin 閱讀(429) | 評論 (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 閱讀(220) | 評論 (0)編輯 收藏

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

          詳細解釋:
          一、DDL is Data Definition Language statements. Some examples:數據定義語言,用于定義和管理 SQL 數據庫中的所有對象的語言
          ????? 1.CREATE - to create objects in the database?? 創建
          ????? 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]。
            下面是對Truncate語句在MSSQLServer2000中用法和原理的說明:
            Truncate table 表名 速度快,而且效率高,因為:
            TRUNCATE TABLE 在功能上與不帶 WHERE 子句的 DELETE 語句相同:二者均刪除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系統和事務日志資源少。
            DELETE 語句每次刪除一行,并在事務日志中為所刪除的每行記錄一項。TRUNCATE TABLE 通過釋放存儲表數據所用的數據頁來刪除數據,并且只在事務日志中記錄頁的釋放。
            TRUNCATE TABLE 刪除表中的所有行,但表結構及其列、約束、索引等保持不變。新行標識所用的計數值重置為該列的種子。如果想保留標識計數值,請改用 DELETE。如果要刪除表定義及其數據,請使用 DROP TABLE 語句。
            對于由 FOREIGN KEY 約束引用的表,不能使用 TRUNCATE TABLE,而應使用不帶 WHERE 子句的 DELETE 語句。由于 TRUNCATE TABLE 不記錄在日志中,所以它不能激活觸發器。
            TRUNCATE TABLE 不能用于參與了索引視圖的表。
          ?????? 5.COMMENT - add comments to the data dictionary 注釋
          ?????? 6.GRANT - gives user's access privileges to database 授權
          ?????? 7.REVOKE - withdraw access privileges given with the GRANT command?? 收回已經授予的權限

          二、DML is Data Manipulation Language statements. Some examples:數據操作語言,SQL中處理數據等操作統稱為數據操縱語言
          ?????? 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執行每一條SQL語句,都必須經過Oracle優化器的評估。所以,了解優化器是如何選擇(搜索)路徑以及索引是如何被使用的,對優化SQL語句有很大的幫助。Explain可以用來迅速方便地查出對于給定SQL語句中的查詢數據是如何得到的即搜索路徑(我們通常稱為Access Path)。從而使我們選擇最優的查詢方式達到最大的優化效果。
          ?????? 7.LOCK TABLE - control concurrency 鎖,用于控制并發

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


          posted @ 2011-08-17 19:40 jadmin 閱讀(113) | 評論 (0)編輯 收藏

          今天啟動Eclipse時,彈出錯誤提示:

          解決辦法:將Eclipse下的eclipse.ini文件做如下改動

          =>

          ?

          posted @ 2011-08-16 17:09 jadmin 閱讀(110) | 評論 (0)編輯 收藏

          1.對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。

          2.應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:

            select id from t where num is null

            可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:

            select id from t where num=0

          3.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

          4.應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:

            select id from t where num=10 or num=20

            可以這樣查詢:

            select id from t where num=10

            union all

            select id from t where num=20

          5.in 和 not in 也要慎用,否則會導致全表掃描,如:

            select id from t where num in(1,2,3)

            對于連續的數值,能用 between 就不要用 in 了:

            select id from t where num between 1 and 3

          6.下面的查詢也將導致全表掃描:

            select id from t where name like '%abc%'

            若要提高效率,可以考慮全文檢索。

          7.如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:

            select id from t where num=@num

            可以改為強制查詢使用索引:

            select id from t with(index(索引名)) where num=@num

          8.應盡量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:

            select id from t where num/2=100

            應改為:

            select id from t where num=100*2

          9.應盡量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:

            select id from t where substring(name,1,3)='abc'--name以abc開頭的id

            select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id

            應改為:

            select id from t where name like 'abc%'

            select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'

          10.不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。

          11.在使用索引字段作為條件時,如果該索引是復合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引,否則該索引將不會被使用,并且應盡可能的讓字段順序與索引順序相一致。

          12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:

            select col1,col2 into #t from t where 1=0

            這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:

            create table #t(...)

          13.很多時候用 exists 代替 in 是一個好的選擇:

            select num from a where num in(select num from b)

            用下面的語句替換:

            select num from a where exists(select 1 from b where num=a.num)

          14.并不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對查詢效

          率起不了作用。

          15.索引并不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

          16.應盡可能的避免更新 clustered 索引數據列,因為 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那么需要考慮是否應將該索引建為 clustered 索引。

          17.盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對于數字型而言只需要比較一次就夠了。

          18.盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長字段存儲空間小,可以節省存儲空間,其次對于查詢來說,在一個相對較小的字段內搜索效率顯然要高些。

          19.任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。

          20.盡量使用表變量來代替臨時表。如果表變量包含大量數據,請注意索引非常有限(只有主鍵索引)。

          21.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。

          22.臨時表并不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對于一次性事件,最好使用導出表。

          23.在新建臨時表時,如果一次性插入數據量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然后insert。

          24.如果使用到了臨時表,在存儲過程的最后務必將所有的臨時表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統表的較長時間鎖定。

          25.盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那么就應該考慮改寫。

          26.使用基于游標的方法或臨時表方法之前,應先尋找基于集的解決方案來解決問題,基于集的方法通常更有效。

          27.與臨時表一樣,游標并不是不可使用。對小型數據集使用 FAST_FORWARD 游標通常要優于其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括“合計”的例程通常要比使用游標執行的速度快。如果開發時間允許,基于游標的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。

          28.在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句后向客戶端發送 DONE_IN_PROC 消息。

          29.盡量避免大事務操作,提高系統并發能力。

          30.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。


          > sql優化方法

          1、使用索引來更快地遍歷表。

            缺省情況下建立的索引是非群集索引,但有時它并不是最佳的。在非群集索引下,數據在物理上隨機存放在數據頁上。合理的索引設計要建立在對各種查詢的分析和預測上。一般來說:

            a.有大量重復值、且經常有范圍查詢( > ,< ,> =,< =)和order by、group by發生的列,可考慮建立群集索引;

            b.經常同時存取多列,且每列都含有重復值可考慮建立組合索引;

            c.組合索引要盡量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列。索引雖有助于提高性能但不是索引越多越好,恰好相反過多的索引會導致系統低效。用戶在表中每加進一個索引,維護索引集合就要做相應的更新工作。

          2、在海量查詢時盡量少用格式轉換。

          3、ORDER BY和GROPU BY:使用ORDER BY和GROUP BY短語,任何一種索引都有助于SELECT的性能提高。

          4、任何對列的操作都將導致表掃描,它包括數據庫教程函數、計算表達式等等,查詢時要盡可能將操作移至等號右邊。

          5、IN、OR子句常會使用工作表,使索引失效。如果不產生大量重復值,可以考慮把子句拆開。拆開的子句中應該包含索引。

          6、只要能滿足你的需求,應盡可能使用更小的數據類型:例如使用MEDIUMINT代替INT

          7、盡量把所有的列設置為NOT NULL,如果你要保存NULL,手動去設置它,而不是把它設為默認值。

          8、盡量少用VARCHAR、TEXT、BLOB類型

          9、如果你的數據只有你所知的少量的幾個。最好使用ENUM類型

          10、正如graymice所講的那樣,建立索引。

          ?

          posted @ 2011-08-13 15:50 jadmin 閱讀(121) | 評論 (0)編輯 收藏

          SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset

          LIMIT子句可以被用于強制SELECT語句返回指定的記錄數。LIMIT接受一個或兩個數字參數,參數必須是一個整數常量。
          如果給定兩個參數,第一個參數指定第一個返回記錄行的偏移量,第二個參數指定返回記錄行的最大數目。
          初始記錄行的偏移量是0(而不是1):為了與 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。

          mysql> SELECT * FROM table LIMIT 5, 10;? // 檢索記錄行 6-15

          //為了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個參數為 -1:
          mysql> SELECT * FROM table LIMIT 95, -1; // 檢索記錄行 96-last.

          //如果只給定一個參數,它表示返回最大的記錄行數目:
          mysql> SELECT * FROM table LIMIT 5;????? //檢索前 5 個記錄行

          //換句話說,LIMIT n 等價于 LIMIT 0,n。

          sql-1.
          SELECT * FROM table WHERE id >= (
          ??? SELECT MAX(id) FROM (
          ?????? SELECT id FROM table ORDER BY id limit 90001
          ??? ) AS tmp
          ) limit 100;

          sql-2.
          SELECT * FROM table WHERE id >= (
          ??? SELECT MAX(id) FROM (
          ?????? SELECT id FROM table ORDER BY id limit 90000, 1
          ??? ) AS tmp
          ) limit 100;

          同樣是取90000條后100條記錄,第1句快還是第2句快?
          第1句是先取了前90001條記錄,取其中最大一個id值作為起始標識,然后利用它可以快速定位下100條記錄
          第2句擇是僅僅取90000條記錄后1條,然后取id值作起始標識定位下100條記錄
          第1句執行結果.100 rows in set (0.23) sec
          第2句執行結果.100 rows in set (0.19) sec

          很明顯第2句勝出.看來limit好像并不完全像我之前想象的那樣做全表掃描返回limit offset+length條記錄,
          這樣看來limit比起MS-SQL的Top性能還是要提高不少的.

          其實sql-2完全可以簡化成:

          SELECT * FROM table WHERE id >= (
          ??? SELECT id FROM table limit 90000, 1
          ) limit 100;

          直接利用第90000條記錄的id,不用經過MAX函數運算,這樣做理論上效率因該高一些,但在實際使用中幾乎看不到效果,
          因為本身定位id返回的就是1條記錄,MAX幾乎不用運作就能得到結果,但這樣寫更清淅明朗,省去了畫蛇那一足.

          可是,既然MySQL有limit可以直接控制取出記錄的位置,為什么不干脆用SELECT id FROM table limit 90000, 1呢?豈不更簡潔?

          ?

          posted @ 2011-08-13 15:47 jadmin 閱讀(120) | 評論 (0)編輯 收藏

          tmp_table_size = 500mb //臨時表大小設置

          //指定用于索引的緩沖區大小,增加它可得到更好的索引處理性能。
          //對于內存在4GB左右的服務器該參數可設置為256M或384M。
          //注意:該參數值設置的過大反而會是服務器整體效率降低!
          key_buffer_size = 384m

          sort_buffer_size = 17mb //排序緩存

          read_buffer_size=4m //讀取緩存

          table_cache=256 //表緩存

          ft_min_word_len //全文搜索

          query_cache_size 查詢緩存

          <?
          #!/bin/sh
          #######檢查mysql狀態
          PORT=`netstat -na | grep "LISTEN" | grep "3306" | awk '{print $4}' | awk -F. '{print $2}'`
          if [ "$PORT" -eq "3306" ]
          ??????? then
          #######檢查mysql占CPU負載
          ??????? mysql_cpu=`top -U root -b -n 1 | grep mysql | awk '{print $10}'|awk -F. '{print $1}'`
          ##如果mysql cpu負載大于80,則重啟mysql
          ??????? if [ "$mysql_cpu" -ge "80" ]
          ??????????????? then
          ??????????????? ps xww |grep 'bin/mysqld_safe' |grep -v grep | awk '{print $1}' | xargs kill -9
          ??????????????? ps xww |grep 'libexec/mysqld' |grep -v grep | awk '{print $1}' | xargs kill -9
          ??????????????? sleep 5
          ??????????????? /usr/local/mysql/bin/mysqld_safe --user=root > /dev/null &
          ??????? else
          ??????????????? exit 0
          ??????? fi
          else
          ???????? /usr/local/mysql/bin/mysqld_safe --user=root > /dev/null &
          fi
          ?>

          影響列數: 4999 (查詢花費 0.1756 秒)
          UPDATE `jobs_faces` SET postime = '1250784000' WHERE jid <505000 AND jid >500000

          jobs_faces字段
          字段 類型 整理 屬性 Null 默認 額外 操作
          jid int(10)?? UNSIGNED 否? auto_increment??????????????
          oid int(10)?? UNSIGNED 否 0???????????????
          cid mediumint(8)?? UNSIGNED 否 0???????????????
          requests smallint(4)?? UNSIGNED 否 0???????????????
          views mediumint(6)?? UNSIGNED 是 0???????????????
          checked tinyint(1)?? UNSIGNED 否 0???????????????
          istoped tinyint(1)?? UNSIGNED 否 0???????????????
          postime int(10)?? UNSIGNED 否 0???????????????
          losetime int(10)?? UNSIGNED 否 0???????????????
          toped tinyint(1)?? UNSIGNED 否 0???????????????
          toptime int(10)?? UNSIGNED 否 0???????????????
          bold tinyint(1)?? UNSIGNED 否 0???????????????
          highlight varchar(7) gbk_chinese_ci? 否????????????????
          lightime int(10)?? UNSIGNED 否 0???????????????
          people smallint(4)?? UNSIGNED 否 0???????????????
          sex tinyint(1)?? UNSIGNED 否 0???????????????
          djobskinds varchar(30) gbk_chinese_ci? 否????????????????
          jname varchar(60) gbk_chinese_ci? 否

          影響列數: 4999 (查詢花費 0.2393 秒)
          UPDATE `jobs_faces` SET postime = '1250784000' WHERE jid <455000 AND jid >450000

          posted @ 2011-08-13 15:45 jadmin 閱讀(122) | 評論 (0)編輯 收藏

          注意:要把php.ini中 extension=php_mbstring.dll 前的;號去掉,重啟apache就可以了。
          我創建三個文件:text1.txt?? text2.txt?? text3.txt
          分別以ASCII? UTF-8? UNICODE 的編碼方式保存

          ?

          <?php
          define ('UTF32_BIG_ENDIAN_BOM',? chr(0x00) . chr(0x00) . chr(0xFE) . chr(0xFF));
          define ('UTF32_LITTLE_ENDIAN_BOM',? chr(0xFF) . chr(0xFE) . chr(0x00) . chr(0x00));
          define ('UTF16_BIG_ENDIAN_BOM',? chr(0xFE) . chr(0xFF));
          define ('UTF16_LITTLE_ENDIAN_BOM', chr(0xFF) . chr(0xFE));
          define ('UTF8_BOM',? chr(0xEF) . chr(0xBB) . chr(0xBF));

          function detect_utf_encoding($text) {
          ??? $first2 = substr($text, 0, 2);
          ??? $first3 = substr($text, 0, 3);
          ??? $first4 = substr($text, 0, 3);
          ? ?
          ??? if ($first3 == UTF8_BOM) return 'UTF-8';
          ??? elseif ($first4 == UTF32_BIG_ENDIAN_BOM) return 'UTF-32BE';
          ??? elseif ($first4 == UTF32_LITTLE_ENDIAN_BOM) return 'UTF-32LE';
          ??? elseif ($first2 == UTF16_BIG_ENDIAN_BOM) return 'UTF-16BE';
          ??? elseif ($first2 == UTF16_LITTLE_ENDIAN_BOM) return 'UTF-16LE';
          }

          function getFileEncoding($str){
          ??? $encoding=mb_detect_encoding($str);
          ??? if(empty($encoding)){
          ??????? $encoding=detect_utf_encoding($str);
          ??? }
          ??? return $encoding;
          }

          $file = 'text1.txt';
          echo getFileEncoding(file_get_contents($file));? // 輸出ASCII
          echo '<br />';

          $file = 'text2.txt';
          echo getFileEncoding(file_get_contents($file));? // 輸出UTF-8
          echo '<br />';


          $file = 'text3.txt';
          echo getFileEncoding(file_get_contents($file));? // 輸出UTF-16LE
          echo '<br />';
          ?>


          posted @ 2011-08-12 20:16 jadmin 閱讀(168) | 評論 (0)編輯 收藏

          1. 下載PostgreSQL數據庫zip版本

          2.? 解壓到D盤,例如:D:\database\postgresql

          3.? cmd窗口進入D:\database\postgresq\bin,依次執行如下命令:
          set PGHOME=D:\database\postgresq
          set PGDATA=%PGHOME%\data
          set PGLIB=%PGHOME%\lib
          set PGHOST=localhost
          set PATH=%PGHOME%\bin;%PATH%

          4.? 添加用戶

          > 添加windows用戶,用于啟動PostgreSQL的windows服務

          D:\database\postgresql>net user postgres pgsqlpw /add /expires:never /passwordchg:no

          > 為保證安全,此用戶不允許本地登錄
          D:\database\postgresql>net localgroup users postgres /del

          > 賦于windows用戶postgres訪問PostgreSQL安裝目錄的權限
          D:\database\postgresql>cacls . /T /E /P postgres:R

          5.? 初始化數據庫

          > 切換到windows用戶postgres的命令行環境
          D:\database\postgresql>runas /noprofile /env /user:postgres "cmd"

          > 初始化數據庫,若不使用-U admin,則數據庫里自動添加當前windows用戶(即postgres)為數據庫帳號
          D:\database\postgresql>bin\initdb -D "D:\database\postgresql\data" -E UTF-8? --locale=chs -A md5 -U admin -W



          6. 啟動PostgreSQL服務:
          pg_ctl -D?D:\database\postgresql\data -l? D:\database\postgresql\pglog.txt start



          7. 創建并連接數據庫:
          createdb test
          psql -h localhost -w -d test



          8. 關閉PostgreSQL服務:
          pg_ctl -D? D:\database\postgresql\data stop

          9. 注冊為Windows服務:

          > 注冊為windows服務,當前windows用戶(即postgres)將作為PostgreSQL服務的登錄用戶
          D:\pgsql>bin\pg_ctl register -N PostgreSQL? -D “D:\database\postgresql\data

          > 啟動PostgreSQL服務
          D:\pgsql> sc start PostgreSQL

          ?

          ?

          posted @ 2011-08-11 20:46 jadmin 閱讀(235) | 評論 (0)編輯 收藏

          postgres=# select uuid_generate_v1();
          uuid_generate_v1
          --------------------------------------
          86811bd4-22a5-11df-b00e-ebd863f5f8a7
          (1 row)

          postgres=# select uuid_generate_v4();
          uuid_generate_v4
          --------------------------------------
          5edbfcbb-1df8-48fa-853f-7917e4e346db
          (1 row)

          主要就是uuid_generate_v1和uuid_generate_v4,當然還有uuid_generate_v3和uuid_generate_v5。

          其他使用可以參見PostgreSQL官方文檔?http://www.postgresql.org/docs/8.3/static/uuid-ossp.html


          posted @ 2011-08-05 18:20 jadmin 閱讀(591) | 評論 (0)編輯 收藏

          > memcache介紹
          Memcached是一個高性能的分布式內存對象緩存系統,用于動態Web應用以減輕數據庫負載。它通過在內存中緩存數據和對象來減少讀取數據庫的次數,從而提供動態、數據庫驅動網站的速度。Memcached基于一個存儲鍵/值對的hashmap。其守護進程(daemon )是用C寫的,但是客戶端可以用任何語言來編寫,并通過memcached協議與守護進程通信。但是它并不提供冗余(例如,復制其hashmap條目);當某個服務器S停止運行或崩潰了,所有存放在S上的鍵/值對都將丟失。


          Memcached官方:http://danga.com/memcached/

          > memcache下載安裝
          下載Windows的Server端,下載地址:http://code.jellycan.com/memcached/

          安裝Memcache Server(也可以不安裝直接啟動)
          1. 下載memcached的windows穩定版,解壓放某個盤下面,比如在c:\memcached
          2. 在CMD下輸入 "c:\memcached\memcached.exe -d install" 安裝.
          3. 再輸入:"c:\memcached\memcached.exe -d start" 啟動。NOTE: 以后memcached將作為windows的一個服務每次開機時自動啟動。這樣服務器端已經安裝完畢了。

          如果下載的是二進制的版本,直接運行就可以了,可以加上參數來加以設置。

          常用設置:
          -p <num>????????? 監聽的端口
          -l <ip_addr>????? 連接的IP地址, 默認是本機
          -d start????????? 啟動memcached服務
          -d restart??????? 重起memcached服務
          -d stop|shutdown? 關閉正在運行的memcached服務
          -d install??????? 安裝memcached服務
          -d uninstall????? 卸載memcached服務
          -u <username>???? 以<username>的身份運行 (僅在以root運行的時候有效)
          -m <num>????????? 最大內存使用,單位MB。默認64MB
          -M??????????????? 內存耗盡時返回錯誤,而不是刪除項
          -c <num>????????? 最大同時連接數,默認是1024
          -f <factor>?????? 塊大小增長因子,默認是1.25
          -n <bytes>??????? 最小分配空間,key+value+flags默認是48
          -h??????????????? 顯示幫助

          然后就可以用java的memcached客戶端來試一下了。

          posted @ 2011-08-01 10:41 jadmin 閱讀(101) | 評論 (0)編輯 收藏

          1 echo()
          可以同時輸出多個字符串,可以多個參數,并不需要圓括號,無返回值。

          2 print()
          只可以同時輸出一個字符串,一個參數,需要圓括號,有返回值,當其執行失敗時返flase .??? print 的用法和C語言很像,所以會對輸出內容里的%做特殊解釋。
          $a=print('hi');
          echo $a;
          //----------------------------
          hi 1?? //1是$a的值。
          //-----------------------------

          3 die();??// 和exit()區別。
          有兩個功能:先輸出內容,然后退出程序。(常用在鏈接服務器,數據庫)
          mysql_connect("locahost","root","root") or die("鏈接服務器失??!");

          4 printf();??? //f指format格式化
          printf("參數1",參數2):
          參數1=按什么格式輸出;參數2=輸出的變量。
          (%s:按字符串;%d:按整型;%b:按二進制;%x:按16進制;%X:按16進制大寫輸出;%o:按八進制; %f:按浮點型)

          對于參數1,其格式如下:
          %[ 'padding_character][-][width][.precision]type

          說明:
          所有轉換都以%開頭,如果想打印一個%,則必須用“%%”;
          參數padding_character是可選的,用來填充變量直至指定的寬度,如:printf ("$%'a10.2f" , 43.2); //$aaaaa43.20,默認是填充一個空格,如果指定了一個空格或0就不需要使用“'”做為前綴。對于任何其它前綴則必須指定單引號。
          【-】是可選的,添加它則表明數據應該左對齊。而不是默認的右對齊,如上例加一個-則為:printf ("$%'a-10.2f" , 43.2); //$43.20aaaaa
          whidth 表示在這里為將被替換的變量留下多少空間(按字符計算)。如上例的10(包括小數點).
          precision則必須是一個小數點開始,表示小數位后面要顯示的位數。

          函數,返回輸出字符個數,把文字格式化以后輸出,如:

          printf ("$%01.2f" , 43.2); //$43.20

          $表示填充的字符

          0表示位數不夠在不影響原值的情況下補0
          1表示輸出的總寬度
          2表示小數位數,有四舍五入

          %f 是表示顯示為一個浮點數

          格式化命令及說明:

          %% 印出百分比符號,不轉換。
          %b 整數轉成二進位。
          %c 整數轉成對應的 ASCII 字符。 如:printf ("$%c" , 65); // 輸出:A
          %d 整數轉成十進位。 如:printf ("$%d" , 65.53); // 輸出:65
          %f 倍精確度數字轉成浮點數。
          %o 整數轉成八進位。
          %s 整數轉成字符串。
          %x 整數轉成小寫十六進位。
          %X 整數轉成大寫十六進位

          對于printf(),還可以使用帶序號并以$符號結束的參數方式來指定參數轉換的順序。如:
          printf ("the total is $%2$.2f and subtotal: %1$.2f" , 65.55,37.2); //the total is $37.20 and subtotal: 65.55
          如上:%2$.2f指定了使用第二個參數65.55,%1$.2f則指定用第一個參數37.20。

          ?? <?php
          ???? $num=100.001;
          ???? printf("%d",$num); //100
          ???? printf("%s",$num); //100.001
          ???? printf("%s---%d---%b---%x---%o---%f",$num,$num,$num,$num,$num,$num)
          ???? //100.001---100---1100100---64---144---1001.00100
          ???? printf("%.2f",$num); //100.00 (小數點保留2位)
          ???? printf("%.1f",$num); //100.0 (小數點保留1位)
          ???? printf("%`#10s",$num); // #10s
          ???? printf("%#10s",$num); //10s
          ?? ?>

          5 sprintf();
          此并不能直接輸出,先賦給一個變量,然后再輸出變量。
          <?php
          $num=100.001;
          $a=sprintf("%d",$num);
          echo $a; //100
          ?>

          6 print_r();
          功能:只用于輸出數組。
          $a = array (1, 2, array ("a", "b", "c"));
          print_r ($a);

          返回:
          Array ( [0] => 1 [1] => 2 [2] => Array ( [0] => a [1] => b [2] => c ) )

          7 var_dump();
          功能: 輸出變量的內容,類型或字符串的內容,類型,長度。常用來調試。
          <?php
          $a=100;
          var_dump($a); //int(100)

          $a=100.356;
          var_dump($a); //float(100.356)
          ?>

          8.var_export ();
          返回關于傳遞給該函數的變量的結構信息,它和 var_dump() 類似,不同的是其返回的表示是合法的 PHP 代碼。
          您可以通過將函數的第二個參數設置為 TRUE,從而返回變量的值。
          <?php
          $a = array (1, 2, array ("a", "b", "c"));
          var_export ($a);
          /* 輸出:
          array (
          0 => 1,
          1 => 2,
          2 =>
          array (
          ?? 0 => 'a',
          ?? 1 => 'b',
          ?? 2 => 'c',
          ),
          )
          */

          $b = 3.1;
          $v = var_export($b, TRUE);
          echo $v;
          /* 輸出:
          3.1
          */
          ?>

          posted @ 2011-07-26 10:09 jadmin 閱讀(81) | 評論 (0)編輯 收藏

          mb_convert_encoding這個函數是用來轉換編碼的。原來一直對程序編碼這一概念不理解,不過現在好像有點開竅了。
          不過英文一般不會存在編碼問題,只有中文數據才會有這個問題。比如你用Zend Studio或Editplus寫程序時,用的是gbk編碼,如果數據需要入數據庫,而數據庫的編碼為utf8時,這時就要把數據進行編碼轉換,不然進到數據庫就會變成亂碼。

          mb_convert_encoding的用法見官方:
          http://cn.php.net/manual/zh/function.mb-convert-encoding.php

          做一個GBK To UTF-8
          < ?php
          header("content-Type: text/html; charset=Utf-8");
          echo mb_convert_encoding("妳係我的友仔", "UTF-8", "GBK");
          ?>

          再來個GB2312 To Big5
          < ?php
          header("content-Type: text/html; charset=big5");
          echo mb_convert_encoding("你是我的朋友", "big5", "GB2312");
          ?>
          不過要使用上面的函數需要安裝但是需要先enable mbstring 擴展庫。

          PHP中的另外一個函數iconv也是用來轉換字符串編碼的,與上函數功能相似。

          下面還有一些詳細的例子:
          iconv — Convert string to requested character encoding
          (PHP 4 >= 4.0.5, PHP 5)
          mb_convert_encoding — Convert character encoding
          (PHP 4 >= 4.0.6, PHP 5)

          用法:
          string mb_convert_encoding ( string str, string to_encoding [, mixed from_encoding] )
          需要先enable mbstring 擴展庫,在 php.ini里將; extension=php_mbstring.dll 前面的 ; 去掉
          mb_convert_encoding 可以指定多種輸入編碼,它會根據內容自動識別,但是執行效率比iconv差太多;

          string iconv ( string in_charset, string out_charset, string str )
          注意:第二個參數,除了可以指定要轉化到的編碼以外,還可以增加兩個后綴://TRANSLIT 和 //IGNORE,其中 //TRANSLIT 會自動將不能直接轉化的字符變成一個或多個近似的字符,//IGNORE 會忽略掉不能轉化的字符,而默認效果是從第一個非法字符截斷。
          Returns the converted string or FALSE on failure.

          使用:
          發現iconv在轉換字符”—”到gb2312時會出錯,如果沒有ignore參數,所有該字符后面的字符串都無法被保存。不管怎么樣,這個”—”都無法轉換成功,無法輸出。 另外mb_convert_encoding沒有這個bug.

          一般情況下用 iconv,只有當遇到無法確定原編碼是何種編碼,或者iconv轉化后無法正常顯示時才用mb_convert_encoding 函數.

          from_encoding is specified by character code name before conversion. it can be array or string - comma separated enumerated list. If it is not specified, the internal encoding will be used.
          /* Auto detect encoding from JIS, eucjp-win, sjis-win, then convert str to UCS-2LE */
          $str = mb_convert_encoding($str, “UCS-2LE”, “JIS, eucjp-win, sjis-win”);
          /* “auto” is expanded to “ASCII,JIS,UTF-8,EUC-JP,SJIS” */
          $str = mb_convert_encoding($str, “EUC-JP”, “auto”);

          例子:
          $content = iconv(”GBK”, “UTF-8″, $content);
          $content = mb_convert_encoding($content, “UTF-8″, “GBK”);

          posted @ 2011-07-23 13:01 jadmin 閱讀(102) | 評論 (0)編輯 收藏

          選擇【Window】菜單
          Preferences ——>General——>Editors——>Text Editors——>Hyperlinking



          posted @ 2011-07-22 10:17 jadmin 閱讀(183) | 評論 (0)編輯 收藏

          <?php
          $photo? = 'http://www.xxx.com/uploads/5908618d80559a594164d984c5ca2b01_32.png';
          if ($photo) {
          ??????? $http = new HttpRequest($photo, HTTP_METH_GET);
          ??????? try {
          ??????????????? $http->send();
          ??????? } catch(Exception $e) {
          ??????????????? try {
          ??????????????????????? $http->send();
          ??????????????? } catch (Exception $e) {
          ??????????????????????? try {
          ??????????????????????????????? $http->send();
          ??????????????????????? } catch (Exception $e) {
          ??????????????????????????????? echo 'error occured while loading file.';
          ??????????????????????????????? exit;
          ??????????????????????? }
          ??????????????? }
          ??????? }
          ??????? if ($http->getResponseCode() == 200) {
          ??????????????? $header = $http->getResponseHeader();
          ??????????????? if (strstr($header['Content-Type'], 'image') !== FALSE) {
          ???????????????????? echo base64_encode($http->getResponseBody());
          ??????????????? }
          ??????? }
          }
          ?>

          posted @ 2011-07-22 09:45 jadmin 閱讀(108) | 評論 (0)編輯 收藏

          今天在MySQL中建立了一張表,其中一個字段是order,通過jdbc往里面插數據一直報錯,好長時間找不到原因

          結果把order字段的名稱改成別的,居然成功插入數據,看來是MySQL字段列名不能使用insert、order等關鍵字


          posted @ 2011-07-12 20:40 jadmin 閱讀(106) | 評論 (0)編輯 收藏

          > 添加curl擴展

          1.在C\windows里的php.ini中我打開了extension=php_curl.dll的功能

          2.把php目錄中的libeay32.dll,ssleay32.dll拷到c:\windows\system32里

          3.重新啟動Apache

          > 代碼

          <?php
          ?? //初始化curl
          ?? $ch = curl_init() or die (curl_error());
          ?? echo "Test for searching 'php' in baidu.";
          ?? //設置URL參數
          ?? curl_setopt($ch,CURLOPT_URL,"http://www.baidu.com/s?wd=php");
          ?? //要求CURL返回數據
          ?? curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
          ?? //執行請求
          ?? $result = curl_exec($ch) or die (curl_error());
          ?? //取得返回的結果,并顯示
          ?? echo $result;
          ?? echo curl_error($ch);
          ?? //關閉CURL
          ?? curl_close($ch);
          ?>

          > 效果

          >CURL函數庫(Client URL Library Function)

          curl_close — 關閉一個curl會話
          curl_copy_handle — 拷貝一個curl連接資源的所有內容和參數
          curl_errno — 返回一個包含當前會話錯誤信息的數字編號
          curl_error — 返回一個包含當前會話錯誤信息的字符串
          curl_exec — 執行一個curl會話
          curl_getinfo — 獲取一個curl連接資源句柄的信息
          curl_init — 初始化一個curl會話
          curl_multi_add_handle — 向curl批處理會話中添加單獨的curl句柄資源
          curl_multi_close — 關閉一個批處理句柄資源
          curl_multi_exec — 解析一個curl批處理句柄
          curl_multi_getcontent — 返回獲取的輸出的文本流
          curl_multi_info_read — 獲取當前解析的curl的相關傳輸信息
          curl_multi_init — 初始化一個curl批處理句柄資源
          curl_multi_remove_handle — 移除curl批處理句柄資源中的某個句柄資源
          curl_multi_select — Get all the sockets associated with the cURL extension, which can then be "selected"
          curl_setopt_array — 以數組的形式為一個curl設置會話參數
          curl_setopt — 為一個curl設置會話參數
          curl_version — 獲取curl相關的版本信息


          關鍵詞:php抓取 ? php庫函數?? curl?? php常用函數


          posted @ 2011-07-08 18:19 jadmin 閱讀(116) | 評論 (0)編輯 收藏

          > 函數date(format,timestamp)
          format???????? 必需。規定時間戳的格式。
          timestamp????? 可選。規定時間戳。默認是當前的日期和時間。
          <?php
          echo date("Y/m/d");
          echo "<br />";
          echo date("Y.m.d");
          echo "<br />";
          echo date("Y-m-d");
          ?>

          > 格式化當前時間

          <?php echo $showtime=date("Y-m-d H:i:s");?>
          顯示的格式: 年-月-日 小時:分鐘:妙
          相關時間參數:
          a - "am" 或是 "pm"
          A - "AM" 或是 "PM"
          d - 幾日,二位數字,若不足二位則前面補零; 如: "01" 至 "31"
          D - 星期幾,三個英文字母; 如: "Fri"
          F - 月份,英文全名; 如: "January"
          h - 12 小時制的小時; 如: "01" 至 "12"
          H - 24 小時制的小時; 如: "00" 至 "23"
          g - 12 小時制的小時,不足二位不補零; 如: "1" 至 12"
          G - 24 小時制的小時,不足二位不補零; 如: "0" 至 "23"
          i - 分鐘; 如: "00" 至 "59"
          j - 幾日,二位數字,若不足二位不補零; 如: "1" 至 "31"
          l - 星期幾,英文全名; 如: "Friday"
          m - 月份,二位數字,若不足二位則在前面補零; 如: "01" 至 "12"
          n - 月份,二位數字,若不足二位則不補零; 如: "1" 至 "12"
          M - 月份,三個英文字母; 如: "Jan"
          s - 秒; 如: "00" 至 "59"
          S - 字尾加英文序數,二個英文字母; 如: "th","nd"
          t - 指定月份的天數; 如: "28" 至 "31"
          U - 總秒數
          w - 數字型的星期幾,如: "0" (星期日) 至 "6" (星期六)
          Y - 年,四位數字; 如: "1999"
          y - 年,二位數字; 如: "99"
          z - 一年中的第幾天; 如: "0" 至 "365"

          ?

          關鍵詞: php學習?? php教程? php格式化時間?? php函數? date()

          ?

          posted @ 2011-07-08 14:58 jadmin 閱讀(117) | 評論 (0)編輯 收藏

          C:\windows\php.ini

          extension=php_xdebug.dll
          xdebug.profiler_enable=on
          xdebug.trace_output_dir="C:/www/test/xdebug"
          xdebug.profiler_output_dir="C:/www/test/xdebug"

          ?

          xdebug.default_enable = On
          xdebug.show_exception_trace = On // 設置為On后,即使捕捉到異常,代碼行仍將強制執行異常跟蹤.
          xdebug.show_local_vars = 1??? // 將打印每個函數調用的最外圍中的所有局部變量,包括尚未初始化的變量
          xdebug.max_nesting_level = 50
          xdebug.var_display_max_depth = 6 // 表示轉儲復雜變量的深度.

          xdebug.dump_once = On
          xdebug.dump_globals = On

          // 如果進一步將 xdebug.dump_undefined 設為 On 并且不設定指定的超全局變量,則仍用值 undefined 打印變量.
          xdebug.dump_undefined = On
          xdebug.dump.REQUEST = *

          // 將打印 PHP 超全局變量 $_SERVER['REQUEST_METHOD']、$_SERVER['REQUEST_URI'] 和 $_SERVER['HTTP_USER_AGENT'].
          xdebug.dump.SERVER = REQUEST_METHOD,REQUEST_URI,HTTP_USER_AGENT

          xdebug.trace_format? 設為 0則輸出將符合人類閱讀習慣(將參數設為 1 則為機器可讀格式).
          xdebug.show_mem_delta = 1 則可以查看內存使用量是在增加還是在減少,????
          xdebug.collect_params = 4 則可以查看傳入參數的類型和值.要監視每個函數返回的值,請設定 xdebug.collect_return = 1.

          PHP Warning:? Xdebug MUST be loaded as a Zend extension in Unknown on line 0?出錯解決

          ;extension=php_xdebug.dll
          zend_extension_ts="C:/php/ext/php_xdebug.dll"????? //以zend方式加載
          xdebug.profiler_enable=on
          xdebug.trace_output_dir="C:/www/test/xdebug"
          xdebug.profiler_output_dir="C:/www/test/xdebug"

          ?

          posted @ 2011-07-07 14:31 jadmin 閱讀(137) | 評論 (0)編輯 收藏

          比如當前文件是放在(d:\www\)下,文件名是test.php。

          <?php?? echo __FILE__ ; // 取得當前文件的絕對地址,結果:D:\www\test.php?? echo dirname(__FILE__); // 取得當前文件所在的絕對目錄,結果:D:\www\?? echo dirname(dirname(__FILE__)); //取得當前文件的上一層目錄名,結果:D:\?>

          使用方法提示,
          dirname(__FILE__) 取到的是當前文件的絕對路徑,也就是說,比起相對路徑,查找速度是最快的。
          如果重復一次可以把目錄往上提升一個層次:
          比如:$d = dirname(dirname(__FILE__));
          其實就是把一個目錄給dirname()做參數了.因為dirname()返回最后的目錄不帶\\或者是/
          所以重復使用的時候可以認為 dirname() 把最下層的目錄當成文件名來處理了.照常返回
          當前目錄的上級目錄.這樣重復就得到了它的上一級的目錄.

          包含得到上一級目錄的文件
          include(dirname(__FILE__).’/../filename.php’);

          posted @ 2011-07-07 13:18 jadmin 閱讀(99) | 評論 (0)編輯 收藏

          本文主要介紹PHP5.2.11 + Apache2.2.19 + MySQL5.1.45的PHP集成運行環境的搭建(Windows XP SP3操作系統環境)

          > 安裝并配置APACHE(安裝到C:\apache)

          ?? 1、安裝時默認安裝,Network Domain, Server Name 我填寫我的計算機名,Administrator's Email Address區域填你的郵件地址
          ?? 2、安裝完后在安裝目錄下有個conf文件夾,打開httpd.conf文件進行配置
          ??????? ·找到 DocumentRoot ,將其設置為你所要存放php, htm等網頁文件的文件夾,如 "D:\phpapache\Apache2.2\htdocs";
          ??????? ·找到 DirectoryIndex ,在index.html后添加index.php, index.htm等,以單個空格將其分開;
          ??????? ·重啟Apache,用http://localhosthttp://127.0.0.1http://yourcompanyname測試是否成功。成功的話屏幕會有個It works!

          > 安裝配置PHP(解壓PHP壓縮包到C:\php)

          ?? 1、將php.ini-recommended文件重命名為php.ini并將其剪到系統所在目錄下(如放在2000/NT的WINNT, XP的Windows目錄下),
          ?? 2、將extension_dir 改為php/ext所在目錄,如 "C:\php\ext";
          ?? 3、將doc_root 改為第一步中的同樣目錄,如 "C:\apache\htdocs";
          ?? 4、找到 ;session.save_path = "/tmp" ,將';'去掉,設置你保存session的目錄,如session.save_path = "C:/php/tmp";
          ?? 5、然后把下面幾句前面的分號去掉,以更好支持Mysql and PHPmyadmin
          ??????? extension=php_mbstring.dll
          ??????? extension=php_gd2.dll
          ??????? extension=php_mysql.dll
          ??????? extension=php_pdo.dll
          ??????? extension=php_pdo_mysql.dll

          > PHP+APACHE整合

          ?? 1、允許Apache將PHP程序作為模塊來運行:
          ?????????? 打開httpd.conf,添加下面內容(位置任意):
          ???????????? LoadModule php5_module "C:/php/php5apache2_2.dll"

          ???????????? AddType application/x-httpd-php .php
          ???????????? AddType application/x-httpd-php .htm
          ??????????? (.htm, .php為可執行php語言的擴展名,也可加html, php3, php4,甚至txt)
          ?????????? (以下兩步可以不需要)
          ?? 2、如果你出于某種原因而需要在CGI模式中運行PHP程序(使用Php.exe),
          ????????? 請將上面這一行變成注釋(各行頭加#即可),添加下面這些行:
          ?????????? # ScriptAlias /php/ "C:/php/"
          ?????????? # AddType application/x-httpd-php .php
          ?????????? #Action application/x-httpd-php "/php/php-cgi.exe"
          ?? 3、現在apache 2 支持HTML而不支持PHP,先把下面幾句加到C:\apache\conf\httpd.conf去:
          ?????????? # ScriptAlias /php/ "C:/php/"
          ?????????? # AddType application/x-httpd-php .php
          ?????????? #Action application/x-httpd-php "/php/php-cgi.exe"

          > 重啟服務,測試環境

          ?? 1、在C:\php里找到php5ts.dll,libmysql.dll將其復制到C:\winnt\system32下(winNT/2000的機器),而winXP/2003是復制到C:\windows\system32下
          ?? 2、測試Apache與php是否連接成功:
          ????????? 啟動start apache服務或者正在運行的就重新啟動restart apache
          ?? 3、在Web根目錄下新建test.php(即C:\apache\htdocs目下)
          ?????????? <html>
          ?????????? <head><title>test</title></head>
          ?????????? <body>
          ??????????? <?php
          ????????????? phpinfo();
          ??????????? ?>
          ???????? </body>
          ????????? </html>

          ?? 4、運行http://localhost/test.php
          ???????? 如果成功,則應該看到一個含有PHP徽標的網頁,其中包含大量設置和其他信息
          ???????? 那么恭喜你,環境已經搭建成功!

          ?

          關鍵詞:PHP?? PHP5? Apache? MySQL? PHP運行環境?

          posted @ 2011-07-07 12:05 jadmin 閱讀(81) | 評論 (0)編輯 收藏

            Hibernate 團隊對外宣布了一個新的家族成員,Hibernate OGM, OGM 是 Object Grid Mapping的縮寫,它的目標是試圖使用 JPA 來操作 NoSQL數據庫,目前似乎局限于Infinispan 。

            目前支持的特性:

          • CRUD operations for entities
          • properties with simple (JDK) types
          • embeddable objects
          • entity hierarchy
          • identifier generators (TABLE and all in-memory based generators today)
          • optimistic locking
          • @ManyToOne,@OneToOne,@OneToManyand@ManyToManyassociations
          • bi-directional associations
          • Set,ListandMapsupport for collections
          • most Hibernate native APIs (likeSession) and JPA APIs (likeEntityManager)
          • same bootstrap model found in JPA or Hibernate Core: in JPA, set<provider>toorg.hibernate.ogm.jpa.HibernateOgmPersistenceand you're good to go

            下載:http://www.hibernate.org/subprojects/ogm/download

            參考手冊:http://docs.jboss.org/hibernate/ogm/3.0/reference/en-US/html_single/

            PS:從目前情況看,不支持流行的 MongoDB 等等。與DataNucleus(http://www.datanucleus.org)在Backend的存儲技術方面,還不能相提并論,DataNucleus支持JDO,JPA標準,支持目前幾乎所有的流行的存儲方式,Google的APPEngine也是基于DataNucleus的。


          posted @ 2011-06-21 12:58 jadmin 閱讀(168) | 評論 (0)編輯 收藏

            ”…在很多領域,專家的作用體現在他們的專業知識上而不是智力上?!?/span>

            --Don Reinertsen

            領域驅動設計(Domain Driven Design)是一種軟件開發方法,目的是讓軟件系統在實現時準確的基于對真實業務過程的建模并根據真實業務過程的調整而調整。

            傳統的開發工作趨向于一種以技術為先導的過程,需求從業務方傳遞到開發團隊,開發人員依據需求上的描述創造出最有可能的假想。

            在瀑布開發過程中,這導致了大量的需要頻繁校對,分析,復核和審批的需求文檔。之后這些文檔被交給開發團隊去變成能夠運行的軟件。

            敏捷開發方法同樣可以采納瀑布模式過程中產生的需求文檔,但敏捷方法在實際的處理過程中會把它們分成很小的任務和“故事”,之后的開發工作將依據這些任務的排序。

            領域驅動設計很大程度上使你從這兩種截然不同的結果中抽身出來,讓你能看到需求是如何在第一現場被收集到——如果你愿意看的話,它在動手先做的方式和在最后一分鐘才做的方式之間做了彌補。

            領域驅動設計方式知道需求是永遠不會“完成”的,需求就像一個活的文檔。更重要的是,這些仍待討論的活文檔實際上就是軟件自身——所有的文檔都是程序代碼的一種影像,一種演示品。

            隨著軟件系統的開發和發展,你對各種問題的理解也會更深——領域驅動設計就是要通過深入的理解問題來找到問題的解決方案。

            然而,領域驅動設計真正的不同之處卻是,它把軟件系統當作業務過程的一個影射,是使能動,而不是驅動。領域驅動設計是要你深入到業務過程中,了解業務術語和實踐方法。技術方面的事被放在了第二位,只是最終的一種手段而已。

            Ubiquitous語言(UL)是領域驅動設計的中心——這是一種共有的不斷成長的語言。它是一種來源于業務術語、經過開發團隊的補充而產生 的協商后的語言。如果一個業務人員不懂得UL里的一個術語,有可能是UL需要改進發展。如果一個技術人員不懂得UL里的一個術語,有可能是他們需要跟領域 專家進行交流。

            領域專家是領域驅動設計里第二重要的組成部分——這些人能夠對這個領域有深入的了解,包括這個業務本身。這些人構成了開發過程中必要的組成部 分。他們也許像一些敏捷開發方法里傳統的產品擁有者那樣不需要“全天候”的在職,但他們必須在開發過程中能被持續的接觸到,而且隨時準備好參與到開發過程 中。領域專家不能被當作門外人,而應被當作領域驅動設計過程中的核心——他們非常像是開發團隊中的一部分,就像普通的開發者和測試者一樣。

            領域驅動設計沒有開始和結束——它是一個不斷的再評估,再重構,再建模,再設計的持續過程——每一次的對話都會使你對問題有更進一步的理解。領 域驅動設計沒有“完成”點——它永遠都在進行;Ubiquitous語言會不斷發展和成長,領域模型隨著對業務理解的改變而改變,代碼不斷的再組織和重構 來更好的表現你的理解。

            各種模擬產物產生又拋棄,而唯一真正有意義的只有代碼。它是解決方案的唯一表達,是一種不再抽象的表達。文檔是用來解釋和描述系統的,而只有代 碼能不失分毫的做到這些。這就是說,在領域驅動設計里,代碼必須保持高質量,要清晰,要有表達力,沒有技術上省略和專門用語,盡可能的要讓代碼能夠在被解 釋時對領域專家有些意義。

            領域驅動設計里沒有精巧的代碼,也沒有奇特的處理過程,或“你不需要知道”的模塊。領域專家不需要成為開發人員來理解軟件系統里用來做這些工作的關鍵部分是什么。他們同樣也不需要考慮數據庫或批處理任務或其他技術相關的方面。

            領域驅動設計是敏捷方法的終極表達——它是用來處理不斷變化和發展的需求的——正如任何一個從未涉足軟件項目的人都知道——一個項目的需求從開始到結束保持一成不變是極其罕見的,絕大多數情況是它會隨著業務的增長和變化而變化。

            通過不斷的交流,領域驅動設計會指導你用軟件最精確的表達你的業務過程。

          ?

          關鍵詞:領域模型???? 設計???? 領域驅動設計

          posted @ 2011-06-11 02:26 jadmin 閱讀(100) | 評論 (0)編輯 收藏

          這是一款開源PHP5寫的MongoDB管理工具,項目地址:http://code.google.com/p/rock-php

          ?

          具體安裝使用可參考wiki --->http://code.google.com/p/rock-php/wiki/rock_mongo_zh

          ?

          關鍵詞:數據庫?? database? MongoDB?? 數據庫連接?? 數據庫管理工具? MongoDB管理工具

          ?

          posted @ 2011-06-10 15:07 jadmin 閱讀(124) | 評論 (0)編輯 收藏

          TimeUnit是一個枚舉類型,可以將時間方便快捷的轉換為(天、時、分、秒、納 秒)day,hour,minute,second,millli...
          有了這個類我們可以方便將時間進行轉換?


          1、我們將1個小時轉換為多少分鐘、多少秒
          ? 1小時轉換分鐘數為60分鐘
          ? TimeUnit.HOURS.toMinutes(1) =>60
          ? 1小時轉換分鐘數為3600秒
          ? TimeUnit.HOURS.toSeconds(1) =>3600
          2、如果將秒轉換為小時、分鐘呢
          ? 3600秒轉換分鐘數為60分鐘
          ? TimeUnit.SECONDS.toMinutes(3600) =>60
          ? 3600秒轉換小時數為1小時
          ? TimeUnit.SECONDS.toHours(3600) =>1

          posted @ 2011-06-10 09:23 jadmin 閱讀(155) | 評論 (0)編輯 收藏

          怎么有效的提高頁面的打開速度,提高網站性能,發現查看網站頁面源代碼的時候,頁面上充斥了無數的空格跟換行,

          增加了頁面的體積,這樣會影響頁面性能,為了有效的解決這個問題,現提供方法如下:

          1、在工程的web.xml上加上如下配置

          <web-app
          ?? xmlns="http://java.sun.com/xml/ns/javaee"
          ?? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ?? xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          ?? metadata-complete="false"
          ?? version="2.5">

          <jsp-config>??
          ?????? <jsp-property-group>??
          ?????????? <url-pattern>*.jsp</url-pattern>??
          ?????????? <trim-directive-whitespaces>true</trim-directive-whitespaces>??
          ?????? </jsp-property-group>???
          </jsp-config>

          2、在每個JSP的頭上加上一段代碼 <%@ page trimDirectiveWhitespaces="true"?%>

          以上兩種方法取其一即可,建議使用第一種。

          PS:

          第一種方式要求:web.xml 中的配置需在servlet2.5、tomcat6.0以上使用才會有效。
          第二種方式要求:jsp版本需要在jsp2.1及以上版本使用才會有效。
          低版本的環境下,使用僅無效果,不會對應用功能造成影響。

          ?

          ?JSP、SERVLET版本查看方式:

          找到tomcat下的lib目錄,查看jsp-api.jar和servlet-api.jar兩個jar包,jar包里面的META-INF文件夾下的MANIFEST.MF文件,里面有相應的版本號
          ?? 如(jsp2.1):
          ?? Name: javax/servlet/jsp/
          ?? Specification-Title: Java API for JavaServer Pages
          ?? Specification-Version: 2.1
          ?? Specification-Vendor: Sun Microsystems, Inc.
          ?? Implementation-Title: javax.servlet.jsp
          ?? Implementation-Version: 2.1.FR
          ?? Implementation-Vendor: Apache Software Foundation

          原理: tomcat在將JSP解釋成JAVA文件時,會根據trim-directive-whitespaces來判斷,生成的代碼在遇到jsp標簽時,是否需要輸出一段代碼:

          out.write("\r\n");

          所以這種去空格的方式是在tomcat每次編譯JSP時,就一次處理的,一旦jsp生成了對應的JAVA,后續的處理過程中,即不再去處理空格的問題,有效的節省資源。

          ?

          posted @ 2011-06-09 18:29 jadmin 閱讀(139) | 評論 (0)編輯 收藏

          簡介:?Spring 的依賴配置方式與 Spring 框架的內核自身是松耦合設計的。然而,直到 Spring 3.0 以前,使用 XML 進行依賴配置幾乎是唯一的選擇。Spring 3.0 的出現改變了這一狀況,它提供了一系列的針對依賴注入的注解,這使得 Spring IoC 在 XML 文件之外多了一種可行的選擇。本文將詳細介紹如何使用這些注解進行依賴配置的管理。

          使用 @Repository、@Service、@Controller 和 @Component 將類標識為 Bean

          Spring 自 2.0 版本開始,陸續引入了一些注解用于簡化 Spring 的開發。@Repository 注解便屬于最先引入的一批,它用于將數據訪問層 (DAO 層 ) 的類標識為 Spring Bean。具體只需將該注解標注在 DAO 類上即可。同時,為了讓 Spring 能夠掃描類路徑中的類并識別出 @Repository 注解,需要在 XML 配置文件中啟用 Bean 的自動掃描功能,這可以通過 <context:component-scan/> 實現。如下所示:

          posted @ 2011-06-09 16:17 jadmin 閱讀(114) | 評論 (0)編輯 收藏

          Java很多ThreadDump中,都可以看到Thin Lock, Fat Lock, Spin Lock,這些Lock都與Java語言、OS有密切的關系。
          回到一個簡單的問題,在Java中,如何實現Synchronizd?
          最簡單的一種做法是,利用OS的mutex機制,把Java的同步(基于Object),翻譯成OS相關的monitor_enter和monitor_exit原語。

          回到Java鎖本身,鎖在不同的應用下有著不同的統計表現,而大部分的統計數據表明,其實線程搶鎖,即鎖競爭,都是短暫的,在大部分的情況下,幾乎都不會發生鎖競爭的現象。
          也就是說,Java鎖,從安全性的角度來看,是有點累贅。
          因此,大量的專家都在鎖上針對這樣的統計特性對Java鎖進行優化。
          其中一種優化方案是,我們對所有的鎖都需要monitor_enter和monitor_exit嗎?事實上不需要。

          如果我們把monitor_enter/monitor_exit看成是Fat Lock方式,則可以把Thin Lock看成是一種基于CAS(Compare and Swap)的簡易實現。
          這兩種鎖,簡單一點理解,就是:

          而基于CAS方式的實現,線程進入競爭狀態的,獲得鎖的線程,會讓其他線程處于自旋狀態(也稱之為Spin Mode,即自旋),這是一種while(Lock_release) doStuff()的Busy-Wait方式,是一種耗CPU的方式;而Fat Lock方式下,一個線程獲得鎖的時候,其他線程可以先sleep,等鎖釋放后,再喚醒(Notify)。
          CAS的優點是快,如果沒有線程競爭的情況下,因為CAS只需要一個指令便獲得鎖,所以稱之為Thin Lock,缺點也是很明顯的,即如果頻繁發生線程競爭,CAS是低效,主要表現為,排斥在鎖之外的線程是Busy Wait狀態;而monitor_enter/monitor_exit/monitor_notify方式,則是重量級的,在線程產生競爭的時候,Fat Lock在OS mutex方式下,可以實現no busy-wait。

          于是,JVM早期版本的做法是,如果T1, T2,T3,T4...產生線程競爭,則T1通過CAS獲得鎖(此時是Thin Lock方式),如果T1在CAS期間獲得鎖,則T2,T3進入SPIN狀態直到T1釋放鎖;而第二個獲得鎖的線程,比如T2,會將鎖升級(Inflation)為Fat Lock,于是,以后嘗試獲得鎖的線程都使用Mutex方式獲得鎖。

          這種設計為鎖提供了兩條路徑:Thin Lock路徑和Fat Lock路徑,大部分情況下,可能都是走Thin Lock路徑,而可能少部分情況,是走Fat Lock路徑,這種方式提供了鎖升級,但是避免不了Busy Wait,而且Thin-Lock升級Fat-Lock之后,沒有辦法回退到Thin-Lock(性能比Fat-Lock更好)。

          Tasuki鎖為這種方式做了2個優化:
          1) 避免CAS導致Busy wait
          2)?Fat Lock可以deflate(與Inflate剛好相反)為Thin Lock(之前是Thin Lock變成Fat Lock之后便不能再回退)。

          經過這樣的改造后,鎖性能提高了10%以上。

          目前,Oracle的BEA JRockit與IBM的JVM都實現了Tasuki鎖機制,唯一的不同是,在鎖實現上都做了不同啟發式的設計,即根據運行時采樣的數據,動態調整一些權值數據,一邊左右Lock Inflation/Lock Defaltion的過程(一顆樹的兩個分支),獲取更好的鎖性能。

          ?

          關鍵詞:JAVA?? 對象鎖?? JVM?? 鎖機制?? JVM鎖?? LOCK


          posted @ 2011-06-09 01:06 jadmin 閱讀(120) | 評論 (0)編輯 收藏
          主站蜘蛛池模板: 花莲市| 井陉县| 赫章县| 福安市| 蕉岭县| 桃源县| 井冈山市| 澄江县| 二连浩特市| 互助| 江西省| 寿光市| 清远市| 桂阳县| 新兴县| 江达县| 平安县| 新竹县| 弥渡县| 陆川县| 湖州市| 台南县| 洛隆县| 微山县| 鄂温| 桃江县| 黔东| 卢氏县| 隆尧县| 习水县| 景德镇市| 西乌| 林口县| 五华县| 房产| 连城县| 黄梅县| 柞水县| 德令哈市| 庆安县| 闻喜县|