
2011年6月11日
> 引言
在Jorm中,主鍵的生成策略主要有AUTO、UUID、GUID、FOREIGN、SEQUENCE、INCREMENT、IDENTITY、ASSIGNED,下面分別來講述這幾種策略的應(yīng)用場(chǎng)景
> GenerationType.AUTO
Jorm的默認(rèn)主鍵策略,自動(dòng)增長(zhǎng)型,自增步長(zhǎng)為1,適用數(shù)據(jù)類型int,long,如:
private int id // 默認(rèn)策略就是AUTO,故可以不寫主鍵策略
或
@Id(GenerationType.AUTO) // 默認(rèn)策略可以省去不寫的哦~
private int id
> GenerationType.INCREMENT
顧名思義,增長(zhǎng)型,適用數(shù)據(jù)類型int,long。自增步長(zhǎng)為1
1> 使用默認(rèn)自增步長(zhǎng)1,如:
@Id(GenerationType.INCREMENT)
@Column("item_id")
private long id;
2> 使用自定義步長(zhǎng),如:
@Id(value = GenerationType.INCREMENT, incrementBy=3) // 這里自增步長(zhǎng)為3,注意寫法
private int id;
> GenerationType.IDENTITY
對(duì)于那些實(shí)現(xiàn)了自動(dòng)增長(zhǎng)的數(shù)據(jù)庫,可以使用IDENTITY,如MySQL,SQL Server,PostreSQL,前提是
MySQL數(shù)據(jù)庫中建表語句定義了主鍵為:id(你的主鍵列名) int NOT NULL AUTO_INCREMENT 或
id(你的主鍵列名) bigint NOT NULL AUTO_INCREMENT
SQL Server數(shù)據(jù)庫中建表語句定義了主鍵為:id int identity(xx, xx) 如此類似
PostreSQL數(shù)據(jù)庫中建表語句定義了主鍵為:id bigserial 或 id serial
使用例子
@Id(GenerationType.IDENTITY)
@Column("id")
private long sid;
> GenerationType.UUID
與數(shù)據(jù)庫無關(guān)的策略,適用數(shù)據(jù)類型:字符串類型,適用所有數(shù)據(jù)庫,長(zhǎng)度須大于或等于32
@Id(GenerationType.UUID)
private String id;
> GenerationType.GUID
與UUID有點(diǎn)類似,不過這個(gè)id值是又?jǐn)?shù)據(jù)庫來生成的,適用于數(shù)據(jù)庫MySQL、PostgreSQL、SQL Server、Oracle等
@Id(GenerationType.GUID)
private String id;
> GenerationType.FOREIGN
適用于一對(duì)一關(guān)系中引用了另一個(gè)對(duì)象的主鍵作為自己的主鍵的情形,如:
@Id(GenerationType.FOREIGN)
@Column("identity_number")
private String identity;
> GenerationType.SEQUENCE
這個(gè)不用多說,應(yīng)用于Oracle、H2、PostgreSQL等有sequence序列功能的數(shù)據(jù)庫
> GenerationType.ASSIGNED
用戶自定義生成,需要由程序員手工給主鍵主動(dòng)賦值
posted @
2011-10-10 15:17 jadmin 閱讀(1492) |
評(píng)論 (3) |
編輯 收藏
直接上代碼吧:
> Demo one
public void batch_op_one() {
session = Jorm.getSession();
JdbcBatcher batcher = session.createBatcher();
batcher.addBatch("delete from t_id_auto");
batcher.addBatch("delete from t_incre");
batcher.addBatch("delete from t_user");
batcher.execute();
session.beginTransaction();
long start;
try {
start = System.currentTimeMillis();
String sql = "INSERT INTO t_user(sex,age,career,name,id) VALUES(?,?,?,?,?)";
for (int i = 0; i < 100000; i++) {
batcher.addBatch(sql, new Object[] {"男", Numbers.random(98), Strings.random(10), Strings.fixed(6), (i+1) });}
String sqlx = "INSERT INTO t_id_auto(name, id) VALUES(?, ?)";
for (int i = 0; i < 100000; i++) {
batcher.addBatch(sqlx, new Object[] {Strings.fixed(6), (i+1)});
if(i > 200) {
//Integer.parseInt("kkk");
}
}
batcher.execute();
System.out.println(System.currentTimeMillis() - start);
} catch (Exception e) {
session.rollback();
} finally {
session.endTransaction();
session.close();
}
}
> Demo two
public void batch_op_two() {
session = Jorm.getSession();
session.beginTransaction();
session.clean(User.class);
JdbcBatcher batcher = session.createBatcher();
batcher.setBatchSize(500);// 指定每批處理的記錄數(shù)
User u;
int times = 20 * 100;
long start = System.currentTimeMillis();
for(int i = 0; i < times; i++) {
String sex = (i % 2 == 0 ? "男" : "女");
u = new User(Strings.fixed(6), sex, Numbers.random(100), Strings.random(16));
batcher.save(u);
}
batcher.execute();
session.endTransaction();
long cost = (System.currentTimeMillis() - start);
System.out.println("Total:" + cost);
System.out.println("Each:" + (float) cost / times);
session.close();
}
項(xiàng)目地址:http://javaclub.sourceforge.net/jorm.html
下載地址: http://sourceforge.net/projects/javaclub/files/jorm/
posted @
2011-10-09 20:09 jadmin 閱讀(1294) |
評(píng)論 (0) |
編輯 收藏
關(guān)系數(shù)據(jù)庫不支持繼承,我們可以做如下的映射,這些映射都是犧牲關(guān)系模式的范式基礎(chǔ)的
?
1, ?用一個(gè)表包含所有繼承層次的所有字段,然后標(biāo)識(shí)列來標(biāo)示是哪個(gè)類。這種映射方法最簡(jiǎn)單,但是是違反規(guī)范化的,而且有些字段要強(qiáng)制為NULL值,無法保證關(guān)系數(shù)據(jù)模型的數(shù)據(jù)完整性,這種映射方式性能最高,最簡(jiǎn)單。
?
2, ?每個(gè)具體類一張表(意思就是父類不需要表),所有父屬性在具體類表中重復(fù),這種映射如果要查詢父類要全部掃描子類表,而且一旦父類變化,這些字表要全部變化。
?
3, ?每個(gè)類一張表,表里只包含所屬類的屬性,然后子類和父類共享外鍵,這種映射避免了第2種的可怕的修改,但是查詢的時(shí)候要執(zhí)行連接。
??????在一般情況下,在新增領(lǐng)域?qū)ο蠛螅夹枰@取對(duì)應(yīng)的主鍵值。使用應(yīng)用層來維護(hù)主鍵,在一定程度上有利于程序性能的優(yōu)化和應(yīng)用移植性的提高。在采用數(shù)據(jù)庫自增主鍵的方案里,如果JDBC驅(qū)動(dòng)不能綁定新增記錄對(duì)應(yīng)的主鍵,就需要手工執(zhí)行查詢語句以獲取對(duì)應(yīng)的主鍵值,對(duì)于高并發(fā)的系統(tǒng),這很容易返回錯(cuò)誤的主鍵。通過帶緩存的DataFieldMaxValueIncrementer,可以一次獲取批量的主鍵值,供多次插入領(lǐng)域?qū)ο髸r(shí)使用,它的執(zhí)行性能是很高的。
??????我們經(jīng)常使用數(shù)據(jù)的自增字段作為表主鍵,也即主鍵值不在應(yīng)用層產(chǎn)生,而是在新增記錄時(shí),由數(shù)據(jù)庫產(chǎn)生。這樣,應(yīng)用層在保存對(duì)象前并不知道對(duì)象主鍵值,而必須在保存數(shù)據(jù)后才能從數(shù)據(jù)庫中返回主鍵值。在很多情況下,我們需要獲取新對(duì)象持久化后的主鍵值。在Hibernate等ORM框架,新對(duì)象持久化后,Hibernate會(huì)自動(dòng)將主鍵值綁定到對(duì)象上,給程序的開發(fā)帶來了很多方便。?
??????在JDBC 3.0規(guī)范中,當(dāng)新增記錄時(shí),允許將數(shù)據(jù)庫自動(dòng)產(chǎn)生的主鍵值綁定到Statement或PreparedStatement中。
??????使用Statement時(shí),可以通過以下方法綁定主鍵值:?int executeUpdate(String sql, int autoGeneratedKeys)?
??????也可以通過Connection創(chuàng)建綁定自增值的PreparedStatement:?PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)?
??????當(dāng)autoGeneratedKeys參數(shù)設(shè)置為Statement.RETURN_GENERATED_KEYS值時(shí)即可綁定數(shù)據(jù)庫產(chǎn)生的主鍵值,設(shè)置為Statement.NO_GENERATED_KEYS時(shí),不綁定主鍵值。下面的代碼演示了Statement綁定并獲取數(shù)據(jù)庫產(chǎn)生的主鍵值的過程:
????? Statement stmt = conn.createStatement();
????? String sql = "INSERT INTO t_topic(topic_title,user_id) VALUES(‘測(cè)試主題’,’123’)";
????? stmt.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS); // ①指定綁定表自增主鍵值
????? ResultSet rs = stmt.getGeneratedKeys();
????? if( rs.next() ) {
?????????? intkey = rs.getInt(); // ②獲取對(duì)應(yīng)的表自增主鍵值
????? }
??????Spring利用這一技術(shù),提供了一個(gè)可以返回新增記錄對(duì)應(yīng)主鍵值的方法:?int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)?,其中第二個(gè)參數(shù)類型org.springframework.jdbc.support.KeyHolder,它是一個(gè)回調(diào)接口,Spring使用它保存新增記錄對(duì)應(yīng)的主鍵,該接口的接口方法描述如下:?
??????Number getKey() throws InvalidDataAccessApiUsageException;
??????當(dāng)僅插入一行數(shù)據(jù),主鍵不是復(fù)合鍵且是數(shù)字類型時(shí),通過該方法可以直接返回新的主鍵值。如果是復(fù)合主鍵,或者有多個(gè)主鍵返回時(shí),該方法拋出 InvalidDataAccessApiUsageException。該方法是最常用的方法,因?yàn)橐话闱闆r下,我們一次僅插入一條數(shù)據(jù)并且主鍵字段類型為數(shù)字類型;?
??????如果是復(fù)合主鍵,則列名和列值構(gòu)成Map中的一個(gè)Entry。如果返回的是多個(gè)主鍵,則拋出InvalidDataAccessApiUsageException異常;?
??????Map getKeys() throws InvalidDataAccessApiUsageException;
??????如果返回多個(gè)主鍵,即PreparedStatement新增了多條記錄,則每一個(gè)主鍵對(duì)應(yīng)一個(gè)Map,多個(gè)Map構(gòu)成一個(gè)List。
??????List getKeyList():?
??????Spring為KeyHolder接口指代了一個(gè)通用的實(shí)現(xiàn)類GeneratedKeyHolder,該類返回新增記錄時(shí)的自增長(zhǎng)主鍵值。假設(shè)我們希望在新增論壇板塊對(duì)象后,希望將主鍵值加載到對(duì)象中,則可以按以下代碼進(jìn)行調(diào)整:
????? public voidaddForum(final Forum forum) {
??????????? final String sql = "INSERT INTO t_forum(forum_name,forum_desc) VALUES(?,?)";
??????????? KeyHolder keyHolder = newGeneratedKeyHolder(); // ①創(chuàng)建一個(gè)主鍵執(zhí)有者
??????????? getJdbcTemplate().update(newPreparedStatementCreator() {
????????????????? public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
??????????????????????? PreparedStatement ps = conn.prepareStatement(sql);
??????????????????????? ps.setString(1, forum.getForumName());
??????????????????????? ps.setString(2, forum.getForumDesc());
??????????????????????? returnps;
????????????????? }
??????????? }, keyHolder);
??????????? forum.setForumId(keyHolder.getKey().intValue()); // ②從主鍵執(zhí)有者中獲取主鍵
????? }
??????這樣,在調(diào)用addForum(Forum forum)新增forum領(lǐng)域?qū)ο蠛螅琭orum將擁有對(duì)應(yīng)的主鍵值,方便后繼的使用。在JDBC 3.0之前的版本中,PreparedStatement不能綁定主鍵,如果采用表自增鍵(如MySQL的auto increment或SQLServer的identity)將給獲取正確的主鍵值帶來挑戰(zhàn)——因?yàn)槟惚仨氃诓迦霐?shù)據(jù)后,馬上執(zhí)行另一條獲取新增主鍵的查詢語句。下面給出了不同數(shù)據(jù)庫獲取最新自增主鍵值的查詢語句:?
1) Assigned
主鍵由外部程序負(fù)責(zé)生成,無需Hibernate參與。
2) hilo
通過hi/lo 算法實(shí)現(xiàn)的主鍵生成機(jī)制,需要額外的數(shù)據(jù)庫表保存主鍵生成歷史狀態(tài)。
3) seqhilo
與hilo 類似,通過hi/lo 算法實(shí)現(xiàn)的主鍵生成機(jī)制,只是主鍵歷史狀態(tài)保存在Sequence中,適用于支持Sequence的數(shù)據(jù)庫,如Oracle。
4) increment
主鍵按數(shù)值順序遞增。此方式的實(shí)現(xiàn)機(jī)制為在當(dāng)前應(yīng)用實(shí)例中維持一個(gè)變量,以保存著當(dāng)前的最大值,之后每次需要生成主鍵的時(shí)候?qū)⒋酥导?作為主鍵。 這種方式可能產(chǎn)生的問題是:如果當(dāng)前有多個(gè)實(shí)例訪問同一個(gè)數(shù)據(jù)庫,那么由于各個(gè)實(shí)例各自維護(hù)主鍵狀態(tài),不同實(shí)例可能生成同樣的主鍵,從而造成主鍵重復(fù)異常。因此,如果同一數(shù)據(jù)庫有多個(gè)實(shí)例訪問,此方式必須避免使用。
5) identity
采用數(shù)據(jù)庫提供的主鍵生成機(jī)制。如DB2、SQL Server、MySQL中的主鍵生成機(jī)制。
6) sequence
采用數(shù)據(jù)庫提供的sequence 機(jī)制生成主鍵。如Oralce 中的Sequence。
7) native
由Hibernate根據(jù)底層數(shù)據(jù)庫自行判斷采用identity、hilo、sequence其中一種作為主鍵生成方式。
8) uuid.hex
由Hibernate基于128 位唯一值產(chǎn)生算法生成16 進(jìn)制數(shù)值(編碼后以長(zhǎng)度32 的字符串表示)作為主鍵。
9) uuid.string
與uuid.hex 類似,只是生成的主鍵未進(jìn)行編碼(長(zhǎng)度16)。在某些數(shù)據(jù)庫中可能出現(xiàn)問題(如PostgreSQL)。
10) foreign
使用外部表的字段作為主鍵。一般而言,利用uuid.hex方式生成主鍵將提供最好的性能和數(shù)據(jù)庫平臺(tái)適應(yīng)性。
另外由于常用的數(shù)據(jù)庫,如Oracle、DB2、SQLServer、MySql 等,都提供了易用的主鍵生成機(jī)制(Auto-Increase 字段或者Sequence)。我們可以在數(shù)據(jù)庫提供的主鍵生成機(jī)制上,采用generator-class=native的主鍵生成方式。不過值得注意的是,一些數(shù)據(jù)庫提供的主鍵生成機(jī)制在效率上未必最佳,
大量并發(fā)insert數(shù)據(jù)時(shí)可能會(huì)引起表之間的互鎖。數(shù)據(jù)庫提供的主鍵生成機(jī)制,往往是通過在一個(gè)內(nèi)部表中保存當(dāng)前主鍵狀態(tài)(如對(duì)于自增型主鍵而言,此內(nèi)部表中就維護(hù)著當(dāng)前的最大值和遞增量), 之后每次插入數(shù)據(jù)會(huì)讀取這個(gè)最大值,然后加上遞增量作為新記錄的主鍵,之后再把這個(gè)新的最大值更新回內(nèi)部表中,這樣,一次Insert操作可能導(dǎo)致數(shù)據(jù)庫內(nèi)部多次表讀寫操作,同時(shí)伴隨的還有數(shù)據(jù)的加鎖解鎖操作,這對(duì)性能產(chǎn)生了較大影響。 因此,對(duì)于并發(fā)Insert要求較高的系統(tǒng),推薦采用uuid.hex 作為主鍵生成機(jī)制。
如果需要采用定制的主鍵生成算法,則在此處配置主鍵生成器,主鍵生成器須實(shí)現(xiàn)org.hibernate.id.IdentifierGenerator 接口
?
關(guān)鍵詞: Hibernate? 主鍵?? 主鍵生成方式? IdentifierGenerator
?
posted @
2011-09-25 13:47 jadmin 閱讀(1007) |
評(píng)論 (0) |
編輯 收藏
摘要:
閱讀全文
posted @
2011-09-23 16:17 jadmin 閱讀(1272) |
評(píng)論 (1) |
編輯 收藏
主要更新:
----------------------------------------
* [35] fix: oracle下一個(gè)分頁取limit數(shù)錯(cuò)誤的bug.
* [34] fix: oracle下檢測(cè)是否支持Savepoints時(shí),一個(gè)未捕獲的異常.
* [33] add: 對(duì)bonecp的支持
* [32] add: 對(duì)proxool的支持
* [31] add: 對(duì)commons-dbcp的支持
* [30] fix: classpath沒有config.properties文件會(huì)報(bào)錯(cuò)
> 引言
有時(shí)候我們有這樣的需求,對(duì)象有一個(gè)屬性可能有多個(gè)值,需要在數(shù)據(jù)庫中作為一個(gè)字段存儲(chǔ)
還是以User為例,career存儲(chǔ)多個(gè)職業(yè)
> 建表
以MySQL為例,執(zhí)行下面的sql建立數(shù)據(jù)表
CREATE TABLE `t_user` (
`id` int(11) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`sex` char(4) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`career` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
> 代碼
實(shí)體類 User.java
@Entity(table = "t_user")
@PK(value = "id")
public class User implements Serializable {
/** desc */
private static final long serialVersionUID = -4750351638245912867L;
@Id
private int id;
private String name;
private String sex;
private Integer age;
@Basic(processor=DefinedFieldProcessor.class)
private String[] career;
@NoColumn
private int kvalue;
public JawaUser() {
super();
}
public JawaUser(String name, String sex, Integer age, String[] career) {
super();
this.name = name;
this.sex = sex;
this.age = age;
this.career = career;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String[] getCareer() {
return career;
}
public void setCareer(String[] career) {
this.career = career;
}
public int getKvalue() {
return kvalue;
}
public void setKvalue(int kvalue) {
this.kvalue = kvalue;
}
public String toString() {
return "User [age=" + age + ", career=" + Arrays.toString(career)
+ ", id=" + id + ", kvalue=" + kvalue + ", name=" + name
+ ", sex=" + sex + "]";
}
}
屬性字段處理類 DefinedFieldProcessor.java
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.javaclub.jorm.Session;
import org.javaclub.jorm.common.CommonUtil;
import org.javaclub.jorm.common.Reflections;
import org.javaclub.jorm.jdbc.process.FieldProcessor;
public class DefinedFieldProcessor implements FieldProcessor {
public Object insert(Session session, Object entity, Field field) {
String[] crs = (String[]) Reflections.getFieldValue(entity, field);
if(!CommonUtil.isEmpty(crs)) {
StringBuilder sbf = new StringBuilder();
for (int i = 0; i < crs.length; i++) {
if(i > 0) {
sbf.append(",");
}
sbf.append(crs[i]);
}
return sbf.toString();
}
return "";
}
public void load(Session session, Object entity, Field field, ResultSet rs,
int idx) throws SQLException {
String str = rs.getString(idx);
String[] crs = str.split(",");
Reflections.setFieldValue(entity, field, crs);
}
}> 測(cè)試
import org.javaclub.jorm.Jorm;
import org.javaclub.jorm.Session;
import org.javaclub.jorm.common.Numbers;
import org.javaclub.jorm.common.Strings;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class FieldProcessorTest {
static Session session;
@BeforeClass
public static void setUpBeforeClass() {
session = Jorm.getSession();
}
@AfterClass
public static void destroy() {
Jorm.free();
}
@Test
public void test_save() {
session.clean(User.class);
User u;
for (int i = 0; i < 100; i++) {
String sex = (i % 2 == 0 ? "男" : "女");
String[] cr = {};
if(i % 3 == 0) {
cr = new String[] {Strings.fixed(2), Strings.random(5), Strings.fixed(6)};
} else if(i % 3 == 1) {
cr = new String[] {Strings.fixed(2), Strings.random(5)};
} else {
cr = new String[] {Strings.fixed(2)};
}
u = new User(Strings.fixed(6), sex, Numbers.random(100), cr);
session.save(u);
}
for (int i = 0; i < 10; i++) {
u = session.read(User.class, i + 1);
System.out.println(u);
}
}
}
posted @
2011-09-22 20:16 jadmin 閱讀(1218) |
評(píng)論 (0) |
編輯 收藏
> 準(zhǔn)備
以MySQL為例,執(zhí)行下面的sql建立數(shù)據(jù)表
CREATE TABLE `t_user` (
`id` int(11) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`sex` char(4) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`career` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
> 引入jar或maven依賴,需要jar包
gerald-jorm-1.0.5.jar 最新版本下載:http://sourceforge.net/projects/javaclub/files
commons-logging-1.1.1.jar
log4j-1.2.14.jar
mysql-connector-java-5.1.6.jar
javassist-3.11.0.GA.jar 或 cglib-nodep-2.2.2.jar (根據(jù)實(shí)際情況選擇性加入)
> 配置文件
在你的java工程的classpath下建立config.properties和jdbc.cfg.xml文件
config.properties內(nèi)容:
# 下面路徑可以根據(jù)實(shí)際情況指定,為相對(duì)classpath的路徑地址
jdbc.config.path=jdbc.cfg.xml
jdbc.cfg.xml內(nèi)容:
<?xml version='1.0' encoding="UTF-8"?>
<jdbc-configuration>
<constant name="show_sql" value="true" />
<constant name="jdbc.batch_size" value="600" />
<constant name="bytecode.provider" value="cglib" />
<connections default="simple">
<connection name="simple">
<property name="connection.implementation">org.javaclub.jorm.jdbc.connection.impl.SimpleConnection</property>
<property name="connection.dialect">MySQLDialect</property>
<property name="connection.driver">com.mysql.jdbc.Driver</property>
<property name="connection.jdbcurl">jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&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&characterEncoding=UTF-8</property>
<property name="connection.database">test</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.pool.min">1</property>
<property name="connection.pool.max">8</property>
<property name="connection.test.sql">select 1</property>
</connection>
</connections>
</jdbc-configuration>
> 實(shí)體類User.java
@PK(value = "id")
@Entity(table="t_user")
public class User {
@Id
private int id;
private String name;
private String sex;
private Integer age;
private String career;
@NoColumn
private int kvalue;
public User() {
super();
}
public User(String name, String sex, Integer age, String career) {
super();
this.name = name;
this.sex = sex;
this.age = age;
this.career = career;
}
public User(Integer id, String name, String sex, Integer age, String career) {
super();
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
this.career = career;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getCareer() {
return career;
}
public void setCareer(String career) {
this.career = career;
}
public int getKvalue() {
return kvalue;
}
public void setKvalue(int kvalue) {
this.kvalue = kvalue;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[" + id + ", " + name + ", " + sex + ", " + age + ", " + career + "]");
return sb.toString();
}
}
這里數(shù)據(jù)庫字段和java實(shí)體類User的屬性在命名上是一致的,如果不一致,比如如果表創(chuàng)建sql為:
CREATE TABLE `t_user` (
`user_id` int(11) NOT NULL,
`user_name` varchar(50) DEFAULT NULL,
`sex` char(4) DEFAULT NULL,
`col_age` int(11) DEFAULT NULL,
`career_job` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
那么對(duì)應(yīng)的實(shí)體User應(yīng)該寫成:
@PK(value = "id")
@Entity(table="t_user")
public class User {
@Id
@Column("user_id")
private int id;
@Column("user_name")
private String name;
// 與數(shù)據(jù)庫字段命名一致,可以不指定@Column
private String sex;
@Column("col_age")
private Integer age;
@Column("career_job")
private String career;
@NoColumn
private int kvalue;
public User() {
super();
}
public User(String name, String sex, Integer age, String career) {
super();
this.name = name;
this.sex = sex;
this.age = age;
this.career = career;
}
public User(Integer id, String name, String sex, Integer age, String career) {
super();
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
this.career = career;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getCareer() {
return career;
}
public void setCareer(String career) {
this.career = career;
}
public int getKvalue() {
return kvalue;
}
public void setKvalue(int kvalue) {
this.kvalue = kvalue;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[" + id + ", " + name + ", " + sex + ", " + age + ", " + career + "]");
return sb.toString();
}
}
> 對(duì)User的增刪查改,UserCrudTest.java,記得引入junit-4.8.2.jar
public class UserCrudTest {
static Session session;
@BeforeClass
public static void before() {
session = Jorm.getSession();
}
@AfterClass
public static void after() {
Jorm.free();
}
@Test
public void save_user() {
session.clean(User.class);
User user = null;
for (int i = 0; i < 600; i++) {
String sex = (i % 2 == 0 ? "男" : "女");
user = new User(Strings.fixed(5), sex, Numbers.random(98), Strings.random(8));
session.save(user);
}
}
@Test // 批量保存
public void batch_save_user() {
session.clean(User.class);
JdbcBatcher batcher = session.createBatcher();
User user = null;
for (int i = 0; i < 600; i++) {
String sex = (i % 2 == 0 ? "男" : "女");
user = new User(Strings.fixed(5), sex, Numbers.random(98), Strings.random(8));
batcher.save(user);
}
batcher.execute();
}
@Test
public void loadUser() {
User user = session.read(User.class, 1);
// 這里user是一個(gè)代理對(duì)象,因?yàn)?#64;Entity(table="t_user", lazy = true)
System.out.println(user.getCareer());// 發(fā)出查詢sql
}
@Test
public void deletUser() {
User user = session.read(User.class, 1);
if(null != user) {
session.delete(user);
}
user = session.read(User.class, 1);
System.out.println(user);
}
@Test
public void test_update_proxy() {
User u;
u = session.read(User.class, 2);
Assert.assertNotNull(u);
Assert.assertTrue(u instanceof JormProxy);
u.setName("Gerald.Chen");
session.update(u);
System.out.println(u.getName());
u = session.read(User.class, 2);
Assert.assertTrue("Gerald.Chen".equals(u.getName()));
}
@Test
public void queryUser() {
SqlParams<User> params = new SqlParams<User>();
params.setObjectClass(User.class);
params.setFirstResult(8);
params.setMaxResults(20);
List<User> users = session.list(params);
System.out.println(users.size());
System.out.println(users);
}
}
posted @
2011-09-21 18:42 jadmin 閱讀(1414) |
評(píng)論 (5) |
編輯 收藏
> 特點(diǎn)
1.支持多數(shù)據(jù)源管理和配置
2.自動(dòng)封裝Entity
3.支持事務(wù)
4.支持存儲(chǔ)過程的方便調(diào)用
5.支持lazy加載
6.支持分頁查詢
7.支持多種數(shù)據(jù)庫H2,MySQL,Oracle,PostgrSQL,SQLServer
> 要求
1.JDK 1.5 or later
2.如需要lazy加載,需要引入cglib或javaassit,具體可配置
> 示例
1.添加
Session session = Jorm.getSession();
User u = new User("Gerald.Chen", "男", 21, "job");;
session.save(u);
2.刪除
session.clean(User.class);// 清空表
session.delete(User.class, "id > 100");// 指定條件刪除
session.delete(user);
3.查詢
User user = session.read(User.class, 1);// 根據(jù)主鍵加載
// 加載第一個(gè)
User user = session.loadFirst(User.class, "(SELECT * FROM t_user WHERE id > ?)", 88);
// 分頁查詢
SqlParams<User> params = new SqlParams<User>("SELECT * FROM t_user WHERE id > ?", new Object[] { 6 });
params.setObjectClass(User.class);
params.setFirstResult(3);
params.setMaxResults(10);
List<User> users = session.list(params);
// 查詢單個(gè)屬性
String sql = "SELECT name FROM t_user WHERE id = 28";
String name = session.queryUniqueObject(sql);
// 查詢屬性列表
List<String> names = session.list(String.class, "SELECT name FROM t_user WHERE id > ?", 200);
List<Integer> ages = session.list(int.class, "SELECT age FROM t_user WHERE age > 18");
4.存儲(chǔ)過程
final String pro = "{? = call hello_proc(?)}";
String r = session.call(new ProcedureCaller() {
public CallableStatement prepare() throws SQLException {
CallableStatement cs = this.getSession().getConnection().prepareCall(pro);
cs.setString(2, "World");
cs.registerOutParameter(1, Types.CHAR);
return cs;
}
public String callback(CallableStatement cs) throws SQLException {
cs.execute();
return cs.getString(1);
}
});
5.事務(wù)
session.clean(User.class);
User u;
session.beginTransaction();
try {
for(int i = 0; i < 1000; i++) {
String sex = (i % 2 == 0 ? "男" : "女");
u = new User(Strings.fixed(6), sex, Numbers.random(100), Strings.random(16));
session.save(u);
if(i == 886) {
Integer.parseInt("kkk");
}
}
session.commit();
} catch (Exception e) {
session.rollback();
} finally {
session.endTransaction();
}
這是一個(gè)完全基于JDBC的輕量java orm framework, 目標(biāo)定位于使用方便,簡(jiǎn)單,后續(xù)會(huì)增加許多新的特性
下載地址:http://sourceforge.net/projects/javaclub/files
> 原理
其實(shí)斷點(diǎn)續(xù)傳的原理很簡(jiǎn)單,就是在 Http 的請(qǐng)求上和一般的下載有所不同而已。
打個(gè)比方,瀏覽器請(qǐng)求服務(wù)器上的一個(gè)文時(shí),所發(fā)出的請(qǐng)求如下:
假設(shè)服務(wù)器域名為 wwww.sjtu.edu.cn,文件名為 down.zip。
GET /down.zip HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive
服務(wù)器收到請(qǐng)求后,按要求尋找請(qǐng)求的文件,提取文件的信息,然后返回給瀏覽器,返回信息如下:
200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT
所謂斷點(diǎn)續(xù)傳,也就是要從文件已經(jīng)下載的地方開始繼續(xù)下載。所以在客戶端瀏覽器傳給 Web 服務(wù)器的時(shí)候要多加一條信息 -- 從哪里開始。
下面是用自己編的一個(gè)"瀏覽器"來傳遞請(qǐng)求信息給 Web 服務(wù)器,要求從 2000070 字節(jié)開始。
GET /down.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=2000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
仔細(xì)看一下就會(huì)發(fā)現(xiàn)多了一行 RANGE: bytes=2000070-
這一行的意思就是告訴服務(wù)器 down.zip 這個(gè)文件從 2000070 字節(jié)開始傳,前面的字節(jié)不用傳了。
服務(wù)器收到這個(gè)請(qǐng)求以后,返回的信息如下:
206
Content-Length=106786028
Content-Range=bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT
和前面服務(wù)器返回的信息比較一下,就會(huì)發(fā)現(xiàn)增加了一行:Content-Range=bytes 2000070-106786027/106786028返回的代碼也改為 206 了,而不再是 200 了。
> 關(guān)鍵點(diǎn)
(1) 用什么方法實(shí)現(xiàn)提交 RANGE: bytes=2000070-。
當(dāng)然用最原始的 Socket 是肯定能完成的,不過那樣太費(fèi)事了,其實(shí) Java 的 net 包中提供了這種功能。代碼如下:
URL url = new URL("http://www.sjtu.edu.cn/down.zip");
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
// 設(shè)置 User-Agent
httpConnection.setRequestProperty("User-Agent","NetFox");
// 設(shè)置斷點(diǎn)續(xù)傳的開始位置
httpConnection.setRequestProperty("RANGE","bytes=2000070");
// 獲得輸入流
InputStream input = httpConnection.getInputStream();
從輸入流中取出的字節(jié)流就是 down.zip 文件從 2000070 開始的字節(jié)流。大家看,其實(shí)斷點(diǎn)續(xù)傳用 Java 實(shí)現(xiàn)起來還是很簡(jiǎn)單的吧。接下來要做的事就是怎么保存獲得的流到文件中去了。
(2)保存文件采用的方法。我采用的是 IO 包中的 RandAccessFile 類。操作相當(dāng)簡(jiǎn)單,假設(shè)從 2000070 處開始保存文件,代碼如下:RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw");long nPos = 2000070;// 定位文件指針到 nPos 位置oSavedFile.seek(nPos);byte[] b = new byte[1024];int nRead;// 從輸入流中讀入字節(jié)流,然后寫到文件中while((nRead=input.read(b,0,1024)) > 0) {???? oSavedFile.write(b,0,nRead);}
?
SymmetricDS是一個(gè)平臺(tái)獨(dú)立的數(shù)據(jù)同步和復(fù)制的解決方案。

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

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

> 問題:給40億個(gè)不重復(fù)的unsigned int的整數(shù),沒排過序的,然后再給幾個(gè)數(shù),如何快速判斷這幾個(gè)數(shù)是否在那40億個(gè)數(shù)當(dāng)中?
> 解決:unsigned int
的取值范圍是0到2^32-1。我們可以申請(qǐng)連續(xù)的2^32/8=512M的內(nèi)存,用每一個(gè)bit對(duì)應(yīng)一個(gè)unsigned
int數(shù)字。首先將512M內(nèi)存都初始化為0,然后每處理一個(gè)數(shù)字就將其對(duì)應(yīng)的bit設(shè)置為1。當(dāng)需要查詢時(shí),直接找到對(duì)應(yīng)bit,看其值是0還是1即可。
lazy的屬性有false、true、extra
false和true用得比較多,extra屬性是不大容易重視的,其實(shí)它和true差不多
extra有個(gè)小的智能的地方是,即調(diào)用集合的size/contains等方法的時(shí)候,hibernate并不會(huì)去加載整個(gè)集合的數(shù)據(jù),而是發(fā)出一條聰明的SQL語句,以便獲得需要的值,只有在真正需要用到這些集合元素對(duì)象數(shù)據(jù)的時(shí)候,才去發(fā)出查詢語句加載所有對(duì)象的數(shù)據(jù)
本文將介紹在Linux(Red Hat 9)環(huán)境下搭建Hadoop集群,此Hadoop集群主要由三臺(tái)機(jī)器組成,主機(jī)名分別為:
linux????? 192.168.35.101
linux02? 192.168.35.102
linux03? 192.168.35.103
從map reduce計(jì)算的角度講,linux作為master節(jié)點(diǎn),linux02和linux03作為slave節(jié)點(diǎn)。
從hdfs數(shù)據(jù)存儲(chǔ)角度講,linux作為namenode節(jié)點(diǎn),linux02和linux03作為datanode節(jié)點(diǎn)。
一臺(tái)namenode機(jī),主機(jī)名為linux,hosts文件內(nèi)容如下:
127.0.0.1?? ??? linux????????? localhost.localdomain????????? localhost
192.168.35.101???? linux????????? linux.localdomain????????????? linux
192.168.35.102???? linux02
192.168.35.103???? linux03
兩臺(tái)datanode機(jī),主機(jī)名為linux02和linux03
>linux02的hosts文件
127.0.0.1 ??? ??? linux02?????? localhost.localdomain?????? localhost
192.168.35.102???? linux02?????? linux02.localdomain???????? linux02
192.168.35.101???? linux
192.168.35.103???? linux03
>inux03的hosts文件
127.0.0.1?? ????? ??? ?linux03????????? localhost.localdomain????????? localhost
192.168.35.103????????? linux03??????????? linux03.localdomain??????????? linux03
192.168.35.101? ??? ?linux
192.168.35.102? ??? ?linux02
1.安裝JDK
> 從java.cun.com下載jdk-6u7-linux-i586.bin
> ftp上傳jdk到linux的root目錄下
> 進(jìn)入root目錄,先后執(zhí)行命令
chmod 755 jdk-6u18-linux-i586-rpm.bin
./jdk-6u18-linux-i586-rpm.bin
一路按提示下去就會(huì)安裝成功
> 配置環(huán)境變量
cd進(jìn)入/etc目錄,vi編輯profile文件,將下面的內(nèi)容追加到文件末尾
export JAVA_HOME=/usr/java/jdk1.6.0_18
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
注意:三臺(tái)機(jī)器都要安裝JDK~
2.設(shè)置Master/Slave機(jī)器之間可以通過SSH無密鑰互相訪問
最好三臺(tái)機(jī)器的使用相同的賬戶名,我是直接使用的root賬戶
操作namenode機(jī)linux:
以用戶root登錄linux,在/root目錄下執(zhí)行下述命令:
ssh-keygen -t rsa
一路回車下去即可在目錄/root/.ssh/下建立兩個(gè)文件id_rsa.pub和id_rsa。
接下來,需要進(jìn)入/root/.ssh目錄,執(zhí)行如下命令:
cd .ssh
再把is_rsa.pub文件復(fù)制到linux02和linux03機(jī)器上去。
scp -r id_rsa.pub root@192.168.35.102:/root/.ssh/authorized_keys_01
scp -r id_rsa.pub root@192.168.35.103:/root/.ssh/authorized_keys_01
操作datanode機(jī)linux02:
以用戶root登錄linux02,在目錄下執(zhí)行命令:
ssh-keygen -t rsa
一路回車下去即可在目錄/root/.ssh/下建立兩個(gè)文件 id_rsa.pub和id_rsa。
接下來,需要進(jìn)入/root/.ssh目錄,執(zhí)行如下命令:
cd .ssh
再把is_rsa.pub文件復(fù)制到namenode機(jī)linux上去。
scp -r id_rsa.pub root@192.168.35.101:/root/.ssh/authorized_keys_02
操作datanode機(jī)linux03:
以用戶root登錄linux03,在目錄下執(zhí)行命令:
ssh-keygen -t rsa
一路回車下去即可在目錄/root/.ssh/下建立兩個(gè)文件 id_rsa.pub和id_rsa。
接下來,需要進(jìn)入/root/.ssh目錄,執(zhí)行如下命令:
cd .ssh
再把is_rsa.pub文件復(fù)制到namenode機(jī)linux上去。
scp -r id_rsa.pub root@192.168.35.101:/root/.ssh/authorized_keys_03
*******************************************************************************
上述方式分別為linux\linux02\linux03機(jī)器生成了rsa密鑰,并且把linux的id_rsa.pub復(fù)制到linux02\linux03上去了,而把linux02和linux03上的id_rsa.pub復(fù)制到linux上去了。
接下來還要完成如下步驟:
linux機(jī):
以root用戶登錄linux,并且進(jìn)入目錄/root/.ssh下,執(zhí)行如下命令:
cat id_rsa.pub >> authorized_keys
cat authorized_keys_02 >> authorized_keys
cat authorized_keys_03 >> authorized_keys
chmod 644 authorized_keys
linux02機(jī):
以root用戶登錄linux02,并且進(jìn)入目錄/root/.ssh下,執(zhí)行如下命令:
cat id_rsa.pub >> authorized_keys
cat authorized_keys_01 >> authorized_keys
chmod 644 authorized_keys
linux03機(jī):
以root用戶登錄linux03,并且進(jìn)入目錄/root/.ssh下,執(zhí)行如下命令:
cat id_rsa.pub >> authorized_keys
cat authorized_keys_01 >> authorized_keys
chmod 644 authorized_keys
通過上述配置,現(xiàn)在以用戶root登錄linux機(jī),既可以無密鑰認(rèn)證方式訪問linux02和linux03了,同樣也可以在linux02和linux03上以ssh linux方式連接到linux上進(jìn)行訪問了。
3.安裝和配置Hadoop
> 在namenode機(jī)器即linux機(jī)上安裝hadoop
我下載的是hadoop-0.20.2.tar.gz,ftp上傳到linux機(jī)的/root目錄上,解壓到安裝目錄/usr/hadoop,最終hadoop的根目錄是/usr/hadoop/hadoop-0.20.2/
編輯/etc/profile文件,在文件尾部追加如下內(nèi)容:
export HADOOP_HOME=/usr/hadoop/hadoop-0.20.2
export PATH=$HADOOP_HOME/bin:$PATH
> 配置Hadoop
core-site.xml:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
?? ?<property>
??????????????? <name>fs.default.name</name>
??????????????? <value>hdfs://192.168.35.101:9000</value>
??????? </property>
??????? <property>
??????????????? <name>hadoop.tmp.dir</name>
??????????????? <value>/tmp/hadoop/hadoop-${user.name}</value>
??????? </property>
</configuration>
hdfs-site.xml:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
??????? <property>
??????????????? <name>dfs.name.dir</name>
??????????????? <value>/home/hadoop/name</value>
??????? </property>
??????? <property>
??????????????? <name>dfs.data.dir</name>
??????????????? <value>/home/hadoop/data</value>
??????? </property>
??????? <property>
??????????????? <name>dfs.replication</name>
??????????????? <value>2</value>
??????? </property>
</configuration>
mapred-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
??????? <property>
??????????????? <name>mapred.job.tracker</name>
??????????????? <value>192.168.35.101:9001</value>
??????? </property>
</configuration>
masters
192.168.35.101
slaves
192.168.35.102
192.168.35.103
至此,hadoop的簡(jiǎn)單配置已經(jīng)完成
> 將在namenode機(jī)器上配置好的hadoop部署到datanode機(jī)器上
這里使用scp命令進(jìn)行遠(yuǎn)程傳輸,先后執(zhí)行命令
scp -r /usr/hadoop/hadoop-0.20.2 root@192.168.35.102:/usr/hadoop/
scp -r /usr/hadoop/hadoop-0.20.2 root@192.168.35.103:/usr/hadoop/
4.測(cè)試
以root用戶登入namenode機(jī)linux,進(jìn)入目錄/usr/hadoop/hadoop-0.20.2/
cd /usr/hadoop/hadoop-0.20.2
> 執(zhí)行格式化
[root@linux hadoop-0.20.2]# bin/hadoop namenode -format
11/07/26 21:16:03 INFO namenode.NameNode: STARTUP_MSG:
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG:?? host = linux/127.0.0.1
STARTUP_MSG:?? args = [-format]
STARTUP_MSG:?? version = 0.20.2
STARTUP_MSG:?? build = https://svn.apache.org/repos/asf/hadoop/common/branches/branch-0.20 -r 911707; compiled by 'chrisdo' on Fri Feb 19 08:07:34 UTC 2010
************************************************************/
Re-format filesystem in /home/hadoop/name ? (Y or N) Y
11/07/26 21:16:07 INFO namenode.FSNamesystem: fsOwner=root,root,bin,daemon,sys,adm,disk,wheel
11/07/26 21:16:07 INFO namenode.FSNamesystem: supergroup=supergroup
11/07/26 21:16:07 INFO namenode.FSNamesystem: isPermissionEnabled=true
11/07/26 21:16:07 INFO common.Storage: Image file of size 94 saved in 0 seconds.
11/07/26 21:16:07 INFO common.Storage: Storage directory /home/hadoop/name has been successfully formatted.
11/07/26 21:16:07 INFO namenode.NameNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at linux/127.0.0.1
************************************************************/
> 啟動(dòng)hadoop
[root@linux hadoop-0.20.2]# bin/start-all.sh
starting namenode, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-namenode-linux.out
192.168.35.102: starting datanode, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-datanode-linux02.out
192.168.35.103: starting datanode, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-datanode-linux03.out
192.168.35.101: starting secondarynamenode, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-secondarynamenode-linux.out
starting jobtracker, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-jobtracker-linux.out
192.168.35.103: starting tasktracker, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-tasktracker-linux03.out
192.168.35.102: starting tasktracker, logging to /usr/hadoop/hadoop-0.20.2/bin/../logs/hadoop-root-tasktracker-linux02.out
[root@linux hadoop-0.20.2]#
> 用jps命令查看進(jìn)程
[root@linux hadoop-0.20.2]# jps
7118 SecondaryNameNode
7343 Jps
6955 NameNode
7204 JobTracker
[root@linux hadoop-0.20.2]#
引言
Hadoop分布式文件系統(tǒng)(HDFS)被設(shè)計(jì)成適
合運(yùn)行在通用硬件(commodity
hardware)上的分布式文件系統(tǒng)。它和現(xiàn)有的分布式文件系統(tǒng)有很多共同點(diǎn)。但同時(shí),它和其他的分布式文件系統(tǒng)的區(qū)別也是很明顯的。HDFS是一個(gè)高
度容錯(cuò)性的系統(tǒng),適合部署在廉價(jià)的機(jī)器上。HDFS能提供高吞吐量的數(shù)據(jù)訪問,非常適合大規(guī)模數(shù)據(jù)集上的應(yīng)用。HDFS放寬了一部分POSIX約束,來實(shí)
現(xiàn)流式讀取文件系統(tǒng)數(shù)據(jù)的目的。HDFS在最開始是作為Apache Nutch搜索引擎項(xiàng)目的基礎(chǔ)架構(gòu)而開發(fā)的。HDFS是Apache Hadoop
Core項(xiàng)目的一部分。這個(gè)項(xiàng)目的地址是http://hadoop.apache.org/core/。
前提和設(shè)計(jì)目標(biāo)
硬件錯(cuò)誤
硬件錯(cuò)誤是常態(tài)而不是異常。HDFS可能由成百上千的服務(wù)器所構(gòu)成,每個(gè)服務(wù)器上存儲(chǔ)著文件系統(tǒng)的部分?jǐn)?shù)據(jù)。我們面對(duì)的現(xiàn)實(shí)是構(gòu)成系統(tǒng)的組件數(shù)目是巨大
的,而且任一組件都有可能失效,這意味著總是有一部分HDFS的組件是不工作的。因此錯(cuò)誤檢測(cè)和快速、自動(dòng)的恢復(fù)是HDFS最核心的架構(gòu)目標(biāo)。
流式數(shù)據(jù)訪問
運(yùn)行在HDFS上的應(yīng)用和普通的應(yīng)用不同,需要流式訪問它們的數(shù)據(jù)集。HDFS的設(shè)計(jì)中更多的考慮到了數(shù)據(jù)批處理,而不是用戶交互處理。比之?dāng)?shù)據(jù)訪問的低
延遲問題,更關(guān)鍵的在于數(shù)據(jù)訪問的高吞吐量。POSIX標(biāo)準(zhǔn)設(shè)置的很多硬性約束對(duì)HDFS應(yīng)用系統(tǒng)不是必需的。為了提高數(shù)據(jù)的吞吐量,在一些關(guān)鍵方面對(duì)
POSIX的語義做了一些修改。
大規(guī)模數(shù)據(jù)集
運(yùn)行在HDFS上的應(yīng)用具有很大的數(shù)據(jù)集。HDFS上的一個(gè)典型文件大小一般都在G字節(jié)至T字節(jié)。因此,HDFS被調(diào)節(jié)以支持大文件存儲(chǔ)。它應(yīng)該能提供整
體上高的數(shù)據(jù)傳輸帶寬,能在一個(gè)集群里擴(kuò)展到數(shù)百個(gè)節(jié)點(diǎn)。一個(gè)單一的HDFS實(shí)例應(yīng)該能支撐數(shù)以千萬計(jì)的文件。
簡(jiǎn)單的一致性模型
HDFS應(yīng)用需要一個(gè)“一次寫入多次讀取”的文件訪問模型。一個(gè)文件經(jīng)過創(chuàng)建、寫入和關(guān)閉之后就不需要改變。這一假設(shè)簡(jiǎn)化了數(shù)據(jù)一致性問題,并且使高吞吐
量的數(shù)據(jù)訪問成為可能。Map/Reduce應(yīng)用或者網(wǎng)絡(luò)爬蟲應(yīng)用都非常適合這個(gè)模型。目前還有計(jì)劃在將來擴(kuò)充這個(gè)模型,使之支持文件的附加寫操作。
“移動(dòng)計(jì)算比移動(dòng)數(shù)據(jù)更劃算”
一個(gè)應(yīng)用請(qǐng)求的計(jì)算,離它操作的數(shù)據(jù)越近就越高效,在數(shù)據(jù)達(dá)到海量級(jí)別的時(shí)候更是如此。因?yàn)檫@樣就能降低網(wǎng)絡(luò)阻塞的影響,提高系統(tǒng)數(shù)據(jù)的吞吐量。將計(jì)算移
動(dòng)到數(shù)據(jù)附近,比之將數(shù)據(jù)移動(dòng)到應(yīng)用所在顯然更好。HDFS為應(yīng)用提供了將它們自己移動(dòng)到數(shù)據(jù)附近的接口。
異構(gòu)軟硬件平臺(tái)間的可移植性
HDFS在設(shè)計(jì)的時(shí)候就考慮到平臺(tái)的可移植性。這種特性方便了HDFS作為大規(guī)模數(shù)據(jù)應(yīng)用平臺(tái)的推廣。
Namenode 和 Datanode
HDFS采用master/slave架構(gòu)。一個(gè)HDFS集群是由一個(gè)Namenode和一定數(shù)目的Datanodes組成。Namenode是一個(gè)中心
服務(wù)器,負(fù)責(zé)管理文件系統(tǒng)的名字空間(namespace)以及客戶端對(duì)文件的訪問。集群中的Datanode一般是一個(gè)節(jié)點(diǎn)一個(gè),負(fù)責(zé)管理它所在節(jié)點(diǎn)上
的存儲(chǔ)。HDFS暴露了文件系統(tǒng)的名字空間,用戶能夠以文件的形式在上面存儲(chǔ)數(shù)據(jù)。從內(nèi)部看,一個(gè)文件其實(shí)被分成一個(gè)或多個(gè)數(shù)據(jù)塊,這些塊存儲(chǔ)在一組
Datanode上。Namenode執(zhí)行文件系統(tǒng)的名字空間操作,比如打開、關(guān)閉、重命名文件或目錄。它也負(fù)責(zé)確定數(shù)據(jù)塊到具體Datanode節(jié)點(diǎn)的
映射。Datanode負(fù)責(zé)處理文件系統(tǒng)客戶端的讀寫請(qǐng)求。在Namenode的統(tǒng)一調(diào)度下進(jìn)行數(shù)據(jù)塊的創(chuàng)建、刪除和復(fù)制。
Namenode和Datanode被設(shè)計(jì)成可以在普通的商用機(jī)器上運(yùn)行。這些機(jī)器一般運(yùn)行著GNU/Linux操作系統(tǒng)(OS)。
HDFS采用Java語言開發(fā),因此任何支持Java的機(jī)器都可以部署Namenode或Datanode。由于采用了可移植性極強(qiáng)的Java語言,使得
HDFS可以部署到多種類型的機(jī)器上。一個(gè)典型的部署場(chǎng)景是一臺(tái)機(jī)器上只運(yùn)行一個(gè)Namenode實(shí)例,而集群中的其它機(jī)器分別運(yùn)行一個(gè)Datanode
實(shí)例。這種架構(gòu)并不排斥在一臺(tái)機(jī)器上運(yùn)行多個(gè)Datanode,只不過這樣的情況比較少見。
集群中單一Namenode的結(jié)構(gòu)大大簡(jiǎn)化了系統(tǒng)的架構(gòu)。Namenode是所有HDFS元數(shù)據(jù)的仲裁者和管理者,這樣,用戶數(shù)據(jù)永遠(yuǎn)不會(huì)流過Namenode。
文件系統(tǒng)的名字空間 (namespace)
HDFS支持傳統(tǒng)的層次型文件組織結(jié)構(gòu)。用戶或者應(yīng)用程序可以創(chuàng)建目錄,然后將文件保存在這些目錄里。文件系統(tǒng)名字空間的層次結(jié)構(gòu)和大多數(shù)現(xiàn)有的文件系統(tǒng)
類似:用戶可以創(chuàng)建、刪除、移動(dòng)或重命名文件。當(dāng)前,HDFS不支持用戶磁盤配額和訪問權(quán)限控制,也不支持硬鏈接和軟鏈接。但是HDFS架構(gòu)并不妨礙實(shí)現(xiàn)
這些特性。
Namenode負(fù)責(zé)維護(hù)文件系統(tǒng)的名字空間,任何對(duì)文件系統(tǒng)名字空間或?qū)傩缘男薷亩紝⒈籒amenode記錄下來。應(yīng)用程序可以設(shè)置HDFS保存的文件的副本數(shù)目。文件副本的數(shù)目稱為文件的副本系數(shù),這個(gè)信息也是由Namenode保存的。
數(shù)據(jù)復(fù)制
HDFS被設(shè)計(jì)成能夠在一個(gè)大集群中跨機(jī)器可靠地存儲(chǔ)超大文件。它將每個(gè)文件存儲(chǔ)成一系列的數(shù)據(jù)塊,除了最后一個(gè),所有的數(shù)據(jù)塊都是同樣大小的。為了容
錯(cuò),文件的所有數(shù)據(jù)塊都會(huì)有副本。每個(gè)文件的數(shù)據(jù)塊大小和副本系數(shù)都是可配置的。應(yīng)用程序可以指定某個(gè)文件的副本數(shù)目。副本系數(shù)可以在文件創(chuàng)建的時(shí)候指
定,也可以在之后改變。HDFS中的文件都是一次性寫入的,并且嚴(yán)格要求在任何時(shí)候只能有一個(gè)寫入者。
Namenode全權(quán)管理數(shù)據(jù)塊的復(fù)制,它周期性地從集群中的每個(gè)Datanode接收心跳信號(hào)和塊狀態(tài)報(bào)告(Blockreport)。接收到心跳信號(hào)意味著該Datanode節(jié)點(diǎn)工作正常。塊狀態(tài)報(bào)告包含了一個(gè)該Datanode上所有數(shù)據(jù)塊的列表。
副本存放: 最最開始的一步
副本的存放是HDFS可靠性和性能的關(guān)鍵。優(yōu)化的副本存放策略是HDFS區(qū)分于其他大部分分布式文件系統(tǒng)的重要特性。這種特性需要做大量的調(diào)優(yōu),并需要經(jīng)
驗(yàn)的積累。HDFS采用一種稱為機(jī)架感知(rack-aware)的策略來改進(jìn)數(shù)據(jù)的可靠性、可用性和網(wǎng)絡(luò)帶寬的利用率。目前實(shí)現(xiàn)的副本存放策略只是在這
個(gè)方向上的第一步。實(shí)現(xiàn)這個(gè)策略的短期目標(biāo)是驗(yàn)證它在生產(chǎn)環(huán)境下的有效性,觀察它的行為,為實(shí)現(xiàn)更先進(jìn)的策略打下測(cè)試和研究的基礎(chǔ)。
大型HDFS實(shí)例一般運(yùn)行在跨越多個(gè)機(jī)架的計(jì)算機(jī)組成的集群上,不同機(jī)架上的兩臺(tái)機(jī)器之間的通訊需要經(jīng)過交換機(jī)。在大多數(shù)情況下,同一個(gè)機(jī)架內(nèi)的兩臺(tái)機(jī)器間的帶寬會(huì)比不同機(jī)架的兩臺(tái)機(jī)器間的帶寬大。
通過一個(gè)機(jī)架感知的
過程,Namenode可以確定每個(gè)Datanode所屬的機(jī)架id。一個(gè)簡(jiǎn)單但沒有優(yōu)化的策略就是將副本存放在不同的機(jī)架上。這樣可以有效防止當(dāng)整個(gè)機(jī)
架失效時(shí)數(shù)據(jù)的丟失,并且允許讀數(shù)據(jù)的時(shí)候充分利用多個(gè)機(jī)架的帶寬。這種策略設(shè)置可以將副本均勻分布在集群中,有利于當(dāng)組件失效情況下的負(fù)載均衡。但是,
因?yàn)檫@種策略的一個(gè)寫操作需要傳輸數(shù)據(jù)塊到多個(gè)機(jī)架,這增加了寫的代價(jià)。
在大多數(shù)情況下,副本系數(shù)是3,HDFS的存放策略是將一個(gè)副本存放在本地機(jī)架的節(jié)點(diǎn)上,一個(gè)副本放在同一機(jī)架的另一個(gè)節(jié)點(diǎn)上,最后一個(gè)副本放在不同機(jī)架
的節(jié)點(diǎn)上。這種策略減少了機(jī)架間的數(shù)據(jù)傳輸,這就提高了寫操作的效率。機(jī)架的錯(cuò)誤遠(yuǎn)遠(yuǎn)比節(jié)點(diǎn)的錯(cuò)誤少,所以這個(gè)策略不會(huì)影響到數(shù)據(jù)的可靠性和可用性。于此
同時(shí),因?yàn)閿?shù)據(jù)塊只放在兩個(gè)(不是三個(gè))不同的機(jī)架上,所以此策略減少了讀取數(shù)據(jù)時(shí)需要的網(wǎng)絡(luò)傳輸總帶寬。在這種策略下,副本并不是均勻分布在不同的機(jī)架
上。三分之一的副本在一個(gè)節(jié)點(diǎn)上,三分之二的副本在一個(gè)機(jī)架上,其他副本均勻分布在剩下的機(jī)架中,這一策略在不損害數(shù)據(jù)可靠性和讀取性能的情況下改進(jìn)了寫
的性能。
當(dāng)前,這里介紹的默認(rèn)副本存放策略正在開發(fā)的過程中。
副本選擇
為了降低整體的帶寬消耗和讀取延時(shí),HDFS會(huì)盡量讓讀取程序讀取離它最近的副本。如果在讀取程序的同一個(gè)機(jī)架上有一個(gè)副本,那么就讀取該副本。如果一個(gè)HDFS集群跨越多個(gè)數(shù)據(jù)中心,那么客戶端也將首先讀本地?cái)?shù)據(jù)中心的副本。
安全模式
Namenode啟動(dòng)后會(huì)進(jìn)入一個(gè)稱為安全模式的特殊狀態(tài)。處于安全模式的Namenode是不會(huì)進(jìn)行數(shù)據(jù)塊的復(fù)制的。Namenode從所有的
Datanode接收心跳信號(hào)和塊狀態(tài)報(bào)告。塊狀態(tài)報(bào)告包括了某個(gè)Datanode所有的數(shù)據(jù)塊列表。每個(gè)數(shù)據(jù)塊都有一個(gè)指定的最小副本數(shù)。當(dāng)
Namenode檢測(cè)確認(rèn)某個(gè)數(shù)據(jù)塊的副本數(shù)目達(dá)到這個(gè)最小值,那么該數(shù)據(jù)塊就會(huì)被認(rèn)為是副本安全(safely
replicated)的;在一定百分比(這個(gè)參數(shù)可配置)的數(shù)據(jù)塊被Namenode檢測(cè)確認(rèn)是安全之后(加上一個(gè)額外的30秒等待時(shí)
間),Namenode將退出安全模式狀態(tài)。接下來它會(huì)確定還有哪些數(shù)據(jù)塊的副本沒有達(dá)到指定數(shù)目,并將這些數(shù)據(jù)塊復(fù)制到其他Datanode上。
文件系統(tǒng)元數(shù)據(jù)的持久化
Namenode上保存著HDFS的名字空間。對(duì)于任何對(duì)文件系統(tǒng)元數(shù)據(jù)產(chǎn)生修改的操作,Namenode都會(huì)使用一種稱為EditLog的事務(wù)日志記錄
下來。例如,在HDFS中創(chuàng)建一個(gè)文件,Namenode就會(huì)在Editlog中插入一條記錄來表示;同樣地,修改文件的副本系數(shù)也將往Editlog插
入一條記錄。Namenode在本地操作系統(tǒng)的文件系統(tǒng)中存儲(chǔ)這個(gè)Editlog。整個(gè)文件系統(tǒng)的名字空間,包括數(shù)據(jù)塊到文件的映射、文件的屬性等,都存
儲(chǔ)在一個(gè)稱為FsImage的文件中,這個(gè)文件也是放在Namenode所在的本地文件系統(tǒng)上。
Namenode在內(nèi)存中保存著整個(gè)文件系統(tǒng)的名字空間和文件數(shù)據(jù)塊映射(Blockmap)的映像。這個(gè)關(guān)鍵的元數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)得很緊湊,因而一個(gè)有4G
內(nèi)存的Namenode足夠支撐大量的文件和目錄。當(dāng)Namenode啟動(dòng)時(shí),它從硬盤中讀取Editlog和FsImage,將所有Editlog中的
事務(wù)作用在內(nèi)存中的FsImage上,并將這個(gè)新版本的FsImage從內(nèi)存中保存到本地磁盤上,然后刪除舊的Editlog,因?yàn)檫@個(gè)舊的
Editlog的事務(wù)都已經(jīng)作用在FsImage上了。這個(gè)過程稱為一個(gè)檢查點(diǎn)(checkpoint)。在當(dāng)前實(shí)現(xiàn)中,檢查點(diǎn)只發(fā)生在Namenode
啟動(dòng)時(shí),在不久的將來將實(shí)現(xiàn)支持周期性的檢查點(diǎn)。
Datanode將HDFS數(shù)據(jù)以文件的形式存儲(chǔ)在本地的文件系統(tǒng)中,它并不知道有關(guān)HDFS文件的信息。它把每個(gè)HDFS數(shù)據(jù)塊存儲(chǔ)在本地文件系統(tǒng)的一
個(gè)單獨(dú)的文件中。Datanode并不在同一個(gè)目錄創(chuàng)建所有的文件,實(shí)際上,它用試探的方法來確定每個(gè)目錄的最佳文件數(shù)目,并且在適當(dāng)?shù)臅r(shí)候創(chuàng)建子目錄。
在同一個(gè)目錄中創(chuàng)建所有的本地文件并不是最優(yōu)的選擇,這是因?yàn)楸镜匚募到y(tǒng)可能無法高效地在單個(gè)目錄中支持大量的文件。當(dāng)一個(gè)Datanode啟動(dòng)時(shí),它
會(huì)掃描本地文件系統(tǒng),產(chǎn)生一個(gè)這些本地文件對(duì)應(yīng)的所有HDFS數(shù)據(jù)塊的列表,然后作為報(bào)告發(fā)送到Namenode,這個(gè)報(bào)告就是塊狀態(tài)報(bào)告。
通訊協(xié)議
所有的HDFS通訊協(xié)議都是建立在TCP/IP協(xié)議之上。客戶端通過一個(gè)可配置的TCP端口連接到Namenode,通過ClientProtocol協(xié)議與Namenode交互。而Datanode使用DatanodeProtocol協(xié)議與Namenode交互。一個(gè)遠(yuǎn)程過程調(diào)用(RPC)模型被抽象出來封裝ClientProtocol和Datanodeprotocol協(xié)議。在設(shè)計(jì)上,Namenode不會(huì)主動(dòng)發(fā)起RPC,而是響應(yīng)來自客戶端或 Datanode 的RPC請(qǐng)求。
健壯性
HDFS的主要目標(biāo)就是即使在出錯(cuò)的情況下也要保證數(shù)據(jù)存儲(chǔ)的可靠性。常見的三種出錯(cuò)情況是:Namenode出錯(cuò), Datanode出錯(cuò)和網(wǎng)絡(luò)割裂(network partitions)。
磁盤數(shù)據(jù)錯(cuò)誤,心跳檢測(cè)和重新復(fù)制
每個(gè)Datanode節(jié)點(diǎn)周期性地向Namenode發(fā)送心跳信號(hào)。網(wǎng)絡(luò)割裂可能導(dǎo)致一部分Datanode跟Namenode失去聯(lián)系。
Namenode通過心跳信號(hào)的缺失來檢測(cè)這一情況,并將這些近期不再發(fā)送心跳信號(hào)Datanode標(biāo)記為宕機(jī),不會(huì)再將新的IO請(qǐng)
求發(fā)給它們。任何存儲(chǔ)在宕機(jī)Datanode上的數(shù)據(jù)將不再有效。Datanode的宕機(jī)可能會(huì)引起一些數(shù)據(jù)塊的副本系數(shù)低于指定值,Namenode不
斷地檢測(cè)這些需要復(fù)制的數(shù)據(jù)塊,一旦發(fā)現(xiàn)就啟動(dòng)復(fù)制操作。在下列情況下,可能需要重新復(fù)制:某個(gè)Datanode節(jié)點(diǎn)失效,某個(gè)副本遭到損
壞,Datanode上的硬盤錯(cuò)誤,或者文件的副本系數(shù)增大。
集群均衡
HDFS的架構(gòu)支持?jǐn)?shù)據(jù)均衡策略。如果某個(gè)Datanode節(jié)點(diǎn)上的空閑空間低于特定的臨界點(diǎn),按照均衡策略系統(tǒng)就會(huì)自動(dòng)地將數(shù)據(jù)從這個(gè)Datanode
移動(dòng)到其他空閑的Datanode。當(dāng)對(duì)某個(gè)文件的請(qǐng)求突然增加,那么也可能啟動(dòng)一個(gè)計(jì)劃創(chuàng)建該文件新的副本,并且同時(shí)重新平衡集群中的其他數(shù)據(jù)。這些均
衡策略目前還沒有實(shí)現(xiàn)。
數(shù)據(jù)完整性
從某個(gè)Datanode獲取的數(shù)據(jù)塊有可能是損壞的,損壞可能是由Datanode的存儲(chǔ)設(shè)備錯(cuò)誤、網(wǎng)絡(luò)錯(cuò)誤或者軟件bug造成的。HDFS客戶端軟件實(shí)
現(xiàn)了對(duì)HDFS文件內(nèi)容的校驗(yàn)和(checksum)檢查。當(dāng)客戶端創(chuàng)建一個(gè)新的HDFS文件,會(huì)計(jì)算這個(gè)文件每個(gè)數(shù)據(jù)塊的校驗(yàn)和,并將校驗(yàn)和作為一個(gè)單
獨(dú)的隱藏文件保存在同一個(gè)HDFS名字空間下。當(dāng)客戶端獲取文件內(nèi)容后,它會(huì)檢驗(yàn)從Datanode獲取的數(shù)據(jù)跟相應(yīng)的校驗(yàn)和文件中的校驗(yàn)和是否匹配,如
果不匹配,客戶端可以選擇從其他Datanode獲取該數(shù)據(jù)塊的副本。
元數(shù)據(jù)磁盤錯(cuò)誤
FsImage和Editlog是HDFS的核心數(shù)據(jù)結(jié)構(gòu)。如果這些文件損壞了,整個(gè)HDFS實(shí)例都將失效。因而,Namenode可以配置成支持維護(hù)多
個(gè)FsImage和Editlog的副本。任何對(duì)FsImage或者Editlog的修改,都將同步到它們的副本上。這種多副本的同步操作可能會(huì)降低
Namenode每秒處理的名字空間事務(wù)數(shù)量。然而這個(gè)代價(jià)是可以接受的,因?yàn)榧词笻DFS的應(yīng)用是數(shù)據(jù)密集的,它們也非元數(shù)據(jù)密集的。當(dāng)
Namenode重啟的時(shí)候,它會(huì)選取最近的完整的FsImage和Editlog來使用。
Namenode是HDFS集群中的單點(diǎn)故障(single point of failure)所在。如果Namenode機(jī)器故障,是需要手工干預(yù)的。目前,自動(dòng)重啟或在另一臺(tái)機(jī)器上做Namenode故障轉(zhuǎn)移的功能還沒實(shí)現(xiàn)。
快照
快照支持某一特定時(shí)刻的數(shù)據(jù)的復(fù)制備份。利用快照,可以讓HDFS在數(shù)據(jù)損壞時(shí)恢復(fù)到過去一個(gè)已知正確的時(shí)間點(diǎn)。HDFS目前還不支持快照功能,但計(jì)劃在將來的版本進(jìn)行支持。
數(shù)據(jù)組織
數(shù)據(jù)塊
HDFS被設(shè)計(jì)成支持大文件,適用HDFS的是那些需要處理大規(guī)模的數(shù)據(jù)集的應(yīng)用。這些應(yīng)用都是只寫入數(shù)據(jù)一次,但卻讀取一次或多次,并且讀取速度應(yīng)能滿
足流式讀取的需要。HDFS支持文件的“一次寫入多次讀取”語義。一個(gè)典型的數(shù)據(jù)塊大小是64MB。因而,HDFS中的文件總是按照64M被切分成不同的
塊,每個(gè)塊盡可能地存儲(chǔ)于不同的Datanode中。
Staging
客戶端創(chuàng)建文件的請(qǐng)求其實(shí)并沒有立即發(fā)送給Namenode,事實(shí)上,在剛開始階段HDFS客戶端會(huì)先將文件數(shù)據(jù)緩存到本地的一個(gè)臨時(shí)文件。應(yīng)用程序的寫
操作被透明地重定向到這個(gè)臨時(shí)文件。當(dāng)這個(gè)臨時(shí)文件累積的數(shù)據(jù)量超過一個(gè)數(shù)據(jù)塊的大小,客戶端才會(huì)聯(lián)系Namenode。Namenode將文件名插入文
件系統(tǒng)的層次結(jié)構(gòu)中,并且分配一個(gè)數(shù)據(jù)塊給它。然后返回Datanode的標(biāo)識(shí)符和目標(biāo)數(shù)據(jù)塊給客戶端。接著客戶端將這塊數(shù)據(jù)從本地臨時(shí)文件上傳到指定的
Datanode上。當(dāng)文件關(guān)閉時(shí),在臨時(shí)文件中剩余的沒有上傳的數(shù)據(jù)也會(huì)傳輸?shù)街付ǖ腄atanode上。然后客戶端告訴Namenode文件已經(jīng)關(guān)
閉。此時(shí)Namenode才將文件創(chuàng)建操作提交到日志里進(jìn)行存儲(chǔ)。如果Namenode在文件關(guān)閉前宕機(jī)了,則該文件將丟失。
上述方法是對(duì)在HDFS上運(yùn)行的目標(biāo)應(yīng)用進(jìn)行認(rèn)真考慮后得到的結(jié)果。這些應(yīng)用需要進(jìn)行文件的流式寫入。如果不采用客戶端緩存,由于網(wǎng)絡(luò)速度和網(wǎng)絡(luò)堵塞會(huì)對(duì)吞估量造成比較大的影響。這種方法并不是沒有先例的,早期的文件系統(tǒng),比如AFS,就用客戶端緩存來提高性能。為了達(dá)到更高的數(shù)據(jù)上傳效率,已經(jīng)放松了POSIX標(biāo)準(zhǔn)的要求。
流水線復(fù)制
當(dāng)客戶端向HDFS文件寫入數(shù)據(jù)的時(shí)候,一開始是寫到本地臨時(shí)文件中。假設(shè)該文件的副本系數(shù)設(shè)置為3,當(dāng)本地臨時(shí)文件累積到一個(gè)數(shù)據(jù)塊的大小時(shí),客戶端會(huì)
從Namenode獲取一個(gè)Datanode列表用于存放副本。然后客戶端開始向第一個(gè)Datanode傳輸數(shù)據(jù),第一個(gè)Datanode一小部分一小部
分(4
KB)地接收數(shù)據(jù),將每一部分寫入本地倉庫,并同時(shí)傳輸該部分到列表中第二個(gè)Datanode節(jié)點(diǎn)。第二個(gè)Datanode也是這樣,一小部分一小部分地
接收數(shù)據(jù),寫入本地倉庫,并同時(shí)傳給第三個(gè)Datanode。最后,第三個(gè)Datanode接收數(shù)據(jù)并存儲(chǔ)在本地。因此,Datanode能流水線式地從
前一個(gè)節(jié)點(diǎn)接收數(shù)據(jù),并在同時(shí)轉(zhuǎn)發(fā)給下一個(gè)節(jié)點(diǎn),數(shù)據(jù)以流水線的方式從前一個(gè)Datanode復(fù)制到下一個(gè)。
可訪問性
HDFS給應(yīng)用提供了多種訪問方式。用戶可以通過Java API接口訪問,也可以通過C語言的封裝API訪問,還可以通過瀏覽器的方式訪問HDFS中的文件。通過WebDAV協(xié)議訪問的方式正在開發(fā)中。
DFSShell
HDFS以文件和目錄的形式組織用戶數(shù)據(jù)。它提供了一個(gè)命令行的接口(DFSShell)讓用戶與HDFS中的數(shù)據(jù)進(jìn)行交互。命令的語法和用戶熟悉的其他shell(例如 bash, csh)工具類似。下面是一些動(dòng)作/命令的示例:
動(dòng)作 | 命令 |
---|
創(chuàng)建一個(gè)名為/foodir的目錄 | bin/hadoop dfs -mkdir /foodir |
創(chuàng)建一個(gè)名為/foodir的目錄 | bin/hadoop dfs -mkdir /foodir |
查看名為/foodir/myfile.txt的文件內(nèi)容 | bin/hadoop dfs -cat /foodir/myfile.txt |
DFSShell 可以用在那些通過腳本語言和文件系統(tǒng)進(jìn)行交互的應(yīng)用程序上。
DFSAdmin
DFSAdmin 命令用來管理HDFS集群。這些命令只有HDSF的管理員才能使用。下面是一些動(dòng)作/命令的示例:
動(dòng)作 | 命令 |
---|
將集群置于安全模式 | bin/hadoop dfsadmin -safemode enter |
顯示Datanode列表 | bin/hadoop dfsadmin -report |
使Datanode節(jié)點(diǎn)datanodename退役 | bin/hadoop dfsadmin -decommission datanodename |
瀏覽器接口
一個(gè)典型的HDFS安裝會(huì)在一個(gè)可配置的TCP端口開啟一個(gè)Web服務(wù)器用于暴露HDFS的名字空間。用戶可以用瀏覽器來瀏覽HDFS的名字空間和查看文件的內(nèi)容。
存儲(chǔ)空間回收
文件的刪除和恢復(fù)
當(dāng)用戶或應(yīng)用程序刪除某個(gè)文件時(shí),這個(gè)文件并沒有立刻從HDFS中刪除。實(shí)際上,HDFS會(huì)將這個(gè)文件重命名轉(zhuǎn)移到/trash目錄。只要文件還在/trash目錄中,該文件就可以被迅速地恢復(fù)。文件在/trash中保存的時(shí)間是可配置的,當(dāng)超過這個(gè)時(shí)間時(shí),Namenode就會(huì)將該文件從名字空間中刪除。刪除文件會(huì)使得該文件相關(guān)的數(shù)據(jù)塊被釋放。注意,從用戶刪除文件到HDFS空閑空間的增加之間會(huì)有一定時(shí)間的延遲。
只要被刪除的文件還在/trash目錄中,用戶就可以恢復(fù)這個(gè)文件。如果用戶想恢復(fù)被刪除的文件,他/她可以瀏覽/trash目錄找回該文件。/trash目錄僅僅保存被刪除文件的最后副本。/trash目錄與其他的目錄沒有什么區(qū)別,除了一點(diǎn):在該目錄上HDFS會(huì)應(yīng)用一個(gè)特殊策略來自動(dòng)刪除文件。目前的默認(rèn)策略是刪除/trash中保留時(shí)間超過6小時(shí)的文件。將來,這個(gè)策略可以通過一個(gè)被良好定義的接口配置。
減少副本系數(shù)
當(dāng)一個(gè)文件的副本系數(shù)被減小后,Namenode會(huì)選擇過剩的副本刪除。下次心跳檢測(cè)時(shí)會(huì)將該信息傳遞給Datanode。Datanode遂即移除相應(yīng)的數(shù)據(jù)塊,集群中的空閑空間加大。同樣,在調(diào)用setReplicationAPI結(jié)束和集群中空閑空間增加間會(huì)有一定的延遲。
參考資料
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;
?}
function remove_quote(&$str) {
?? ??? ?if (preg_match("/^\"/",$str)){
?? ??? ??? ?$str = substr($str, 1, strlen($str) - 1);
?? ??? ?}
?? ??? ?//判斷字符串是否以'"'結(jié)束
?? ??? ?if (preg_match("/\"$/",$str)){
?? ??? ??? ?$str = substr($str, 0, strlen($str) - 1);;
?? ??? ?}
?? ??? ?return $str;
? }
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'; ?
????????????? } ?
??????? }?
?? }
DML(data manipulation language):
?????? 它們是SELECT、UPDATE、INSERT、DELETE,就象它的名字一樣,這4條命令是用來對(duì)數(shù)據(jù)庫里的數(shù)據(jù)進(jìn)行操作的語言
DDL(data definition language):
?????? DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定義或改變表(TABLE)的結(jié)構(gòu),數(shù)據(jù)類型,表之間的鏈接和約束等初始化工作上,他們大多在建立表時(shí)使用
DCL(Data Control Language):
?????? 是數(shù)據(jù)庫控制功能。是用來設(shè)置或更改數(shù)據(jù)庫用戶或角色權(quán)限的語句,包括(grant,deny,revoke等)語句。在默認(rèn)狀態(tài)下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人員才有權(quán)力執(zhí)行DCL
詳細(xì)解釋:
一、DDL is Data Definition Language statements. Some examples:數(shù)據(jù)定義語言,用于定義和管理 SQL 數(shù)據(jù)庫中的所有對(duì)象的語言
????? 1.CREATE - to create objects in the database?? 創(chuàng)建
????? 2.ALTER - alters the structure of the database?? 修改
????? 3.DROP - delete objects from the database?? 刪除
????? 4.TRUNCATE - remove all records from a table, including all spaces allocated for the records are removed
????? TRUNCATE TABLE [Table Name]。
下面是對(duì)Truncate語句在MSSQLServer2000中用法和原理的說明:
Truncate table 表名 速度快,而且效率高,因?yàn)?
TRUNCATE TABLE 在功能上與不帶 WHERE 子句的 DELETE 語句相同:二者均刪除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系統(tǒng)和事務(wù)日志資源少。
DELETE 語句每次刪除一行,并在事務(wù)日志中為所刪除的每行記錄一項(xiàng)。TRUNCATE TABLE 通過釋放存儲(chǔ)表數(shù)據(jù)所用的數(shù)據(jù)頁來刪除數(shù)據(jù),并且只在事務(wù)日志中記錄頁的釋放。
TRUNCATE TABLE 刪除表中的所有行,但表結(jié)構(gòu)及其列、約束、索引等保持不變。新行標(biāo)識(shí)所用的計(jì)數(shù)值重置為該列的種子。如果想保留標(biāo)識(shí)計(jì)數(shù)值,請(qǐng)改用 DELETE。如果要?jiǎng)h除表定義及其數(shù)據(jù),請(qǐng)使用 DROP TABLE 語句。
對(duì)于由 FOREIGN KEY 約束引用的表,不能使用 TRUNCATE TABLE,而應(yīng)使用不帶 WHERE 子句的 DELETE 語句。由于 TRUNCATE TABLE 不記錄在日志中,所以它不能激活觸發(fā)器。
TRUNCATE TABLE 不能用于參與了索引視圖的表。
?????? 5.COMMENT - add comments to the data dictionary 注釋
?????? 6.GRANT - gives user's access privileges to database 授權(quán)
?????? 7.REVOKE - withdraw access privileges given with the GRANT command?? 收回已經(jīng)授予的權(quán)限
二、DML is Data Manipulation Language statements. Some examples:數(shù)據(jù)操作語言,SQL中處理數(shù)據(jù)等操作統(tǒng)稱為數(shù)據(jù)操縱語言
?????? 1.SELECT - retrieve data from the a database?????????? 查詢
?????? 2.INSERT - insert data into a table??????????????????? 添加
?????? 3.UPDATE - updates existing data within a table??? 更新
?????? 4.DELETE - deletes all records from a table, the space for the records remain?? 刪除
?????? 5.CALL - call a PL/SQL or Java subprogram
?????? 6.EXPLAIN PLAN - explain access path to data
?????? Oracle RDBMS執(zhí)行每一條SQL語句,都必須經(jīng)過Oracle優(yōu)化器的評(píng)估。所以,了解優(yōu)化器是如何選擇(搜索)路徑以及索引是如何被使用的,對(duì)優(yōu)化SQL語句有很大的幫助。Explain可以用來迅速方便地查出對(duì)于給定SQL語句中的查詢數(shù)據(jù)是如何得到的即搜索路徑(我們通常稱為Access Path)。從而使我們選擇最優(yōu)的查詢方式達(dá)到最大的優(yōu)化效果。
?????? 7.LOCK TABLE - control concurrency 鎖,用于控制并發(fā)
三、DCL is Data Control Language statements. Some examples:數(shù)據(jù)控制語言,用來授予或回收訪問數(shù)據(jù)庫的某種特權(quán),并控制數(shù)據(jù)庫操縱事務(wù)發(fā)生的時(shí)間及效果,對(duì)數(shù)據(jù)庫實(shí)行監(jiān)視等
?????? 1.COMMIT - save work done 提交
?????? 2.SAVEPOINT - identify a point in a transaction to which you can later roll back 保存點(diǎn)
?????? 3.ROLLBACK - restore database to original since the last COMMIT?? 回滾
?????? 4.SET TRANSACTION - Change transaction options like what rollback segment to use?? 設(shè)置當(dāng)前事務(wù)的特性,它對(duì)后面的事務(wù)沒有影響.
今天啟動(dòng)Eclipse時(shí),彈出錯(cuò)誤提示:

解決辦法:將Eclipse下的eclipse.ini文件做如下改動(dòng)
=>

?
1.對(duì)查詢進(jìn)行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引。
2.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
select id from t where num is null
可以在num上設(shè)置默認(rèn)值0,確保表中num列沒有null值,然后這樣查詢:
select id from t where num=0
3.應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進(jìn)行全表掃描。
4.應(yīng)盡量避免在 where 子句中使用 or 來連接條件,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
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 也要慎用,否則會(huì)導(dǎo)致全表掃描,如:
select id from t where num in(1,2,3)
對(duì)于連續(xù)的數(shù)值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查詢也將導(dǎo)致全表掃描:
select id from t where name like '%abc%'
若要提高效率,可以考慮全文檢索。
7.如果在 where 子句中使用參數(shù),也會(huì)導(dǎo)致全表掃描。因?yàn)镾QL只有在運(yùn)行時(shí)才會(huì)解析局部變量,但優(yōu)化程序不能將訪問計(jì)劃的選擇推遲到運(yùn)行時(shí);它必須在編譯時(shí)進(jìn)行選擇。然而,如果在編譯時(shí)建立訪問計(jì)劃,變量的值還是未知的,因而無法作為索引選擇的輸入項(xiàng)。如下面語句將進(jìn)行全表掃描:
select id from t where num=@num
可以改為強(qiáng)制查詢使用索引:
select id from t with(index(索引名)) where num=@num
8.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
select id from t where num/2=100
應(yīng)改為:
select id from t where num=100*2
9.應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
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
應(yīng)改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
10.不要在 where 子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無法正確使用索引。
11.在使用索引字段作為條件時(shí),如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個(gè)字段作為條件時(shí)才能保證系統(tǒng)使用該索引,否則該索引將不會(huì)被使用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。
12.不要寫一些沒有意義的查詢,如需要生成一個(gè)空表結(jié)構(gòu):
select col1,col2 into #t from t where 1=0
這類代碼不會(huì)返回任何結(jié)果集,但是會(huì)消耗系統(tǒng)資源的,應(yīng)改成這樣:
create table #t(...)
13.很多時(shí)候用 exists 代替 in 是一個(gè)好的選擇:
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.并不是所有索引對(duì)查詢都有效,SQL是根據(jù)表中數(shù)據(jù)來進(jìn)行查詢優(yōu)化的,當(dāng)索引列有大量數(shù)據(jù)重復(fù)時(shí),SQL查詢可能不會(huì)去利用索引,如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對(duì)查詢效
率起不了作用。
15.索引并不是越多越好,索引固然可以提高相應(yīng)的 select 的效率,但同時(shí)也降低了 insert 及 update 的效率,因?yàn)?insert 或 update 時(shí)有可能會(huì)重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個(gè)表的索引數(shù)最好不要超過6個(gè),若太多則應(yīng)考慮一些不常使用到的列上建的索引是否有必要。
16.應(yīng)盡可能的避免更新 clustered 索引數(shù)據(jù)列,因?yàn)?clustered 索引數(shù)據(jù)列的順序就是表記錄的物理存儲(chǔ)順序,一旦該列值改變將導(dǎo)致整個(gè)表記錄的順序的調(diào)整,會(huì)耗費(fèi)相當(dāng)大的資源。若應(yīng)用系統(tǒng)需要頻繁更新 clustered 索引數(shù)據(jù)列,那么需要考慮是否應(yīng)將該索引建為 clustered 索引。
17.盡量使用數(shù)字型字段,若只含數(shù)值信息的字段盡量不要設(shè)計(jì)為字符型,這會(huì)降低查詢和連接的性能,并會(huì)增加存儲(chǔ)開銷。這是因?yàn)橐嬖谔幚聿樵兒瓦B接時(shí)會(huì)逐個(gè)比較字符串中每一個(gè)字符,而對(duì)于數(shù)字型而言只需要比較一次就夠了。
18.盡可能的使用 varchar/nvarchar 代替 char/nchar ,因?yàn)槭紫茸冮L(zhǎng)字段存儲(chǔ)空間小,可以節(jié)省存儲(chǔ)空間,其次對(duì)于查詢來說,在一個(gè)相對(duì)較小的字段內(nèi)搜索效率顯然要高些。
19.任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
20.盡量使用表變量來代替臨時(shí)表。如果表變量包含大量數(shù)據(jù),請(qǐng)注意索引非常有限(只有主鍵索引)。
21.避免頻繁創(chuàng)建和刪除臨時(shí)表,以減少系統(tǒng)表資源的消耗。
22.臨時(shí)表并不是不可使用,適當(dāng)?shù)厥褂盟鼈兛梢允鼓承├谈行В纾?dāng)需要重復(fù)引用大型表或常用表中的某個(gè)數(shù)據(jù)集時(shí)。但是,對(duì)于一次性事件,最好使用導(dǎo)出表。
23.在新建臨時(shí)表時(shí),如果一次性插入數(shù)據(jù)量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,應(yīng)先create table,然后insert。
24.如果使用到了臨時(shí)表,在存儲(chǔ)過程的最后務(wù)必將所有的臨時(shí)表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統(tǒng)表的較長(zhǎng)時(shí)間鎖定。
25.盡量避免使用游標(biāo),因?yàn)橛螛?biāo)的效率較差,如果游標(biāo)操作的數(shù)據(jù)超過1萬行,那么就應(yīng)該考慮改寫。
26.使用基于游標(biāo)的方法或臨時(shí)表方法之前,應(yīng)先尋找基于集的解決方案來解決問題,基于集的方法通常更有效。
27.與臨時(shí)表一樣,游標(biāo)并不是不可使用。對(duì)小型數(shù)據(jù)集使用 FAST_FORWARD 游標(biāo)通常要優(yōu)于其他逐行處理方法,尤其是在必須引用幾個(gè)表才能獲得所需的數(shù)據(jù)時(shí)。在結(jié)果集中包括“合計(jì)”的例程通常要比使用游標(biāo)執(zhí)行的速度快。如果開發(fā)時(shí)間允許,基于游標(biāo)的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。
28.在所有的存儲(chǔ)過程和觸發(fā)器的開始處設(shè)置 SET NOCOUNT ON ,在結(jié)束時(shí)設(shè)置 SET NOCOUNT OFF 。無需在執(zhí)行存儲(chǔ)過程和觸發(fā)器的每個(gè)語句后向客戶端發(fā)送 DONE_IN_PROC 消息。
29.盡量避免大事務(wù)操作,提高系統(tǒng)并發(fā)能力。
30.盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過大,應(yīng)該考慮相應(yīng)需求是否合理。
> sql優(yōu)化方法
1、使用索引來更快地遍歷表。
缺省情況下建立的索引是非群集索引,但有時(shí)它并不是最佳的。在非群集索引下,數(shù)據(jù)在物理上隨機(jī)存放在數(shù)據(jù)頁上。合理的索引設(shè)計(jì)要建立在對(duì)各種查詢的分析和預(yù)測(cè)上。一般來說:
a.有大量重復(fù)值、且經(jīng)常有范圍查詢( > ,< ,> =,< =)和order by、group by發(fā)生的列,可考慮建立群集索引;
b.經(jīng)常同時(shí)存取多列,且每列都含有重復(fù)值可考慮建立組合索引;
c.組合索引要盡量使關(guān)鍵查詢形成索引覆蓋,其前導(dǎo)列一定是使用最頻繁的列。索引雖有助于提高性能但不是索引越多越好,恰好相反過多的索引會(huì)導(dǎo)致系統(tǒng)低效。用戶在表中每加進(jìn)一個(gè)索引,維護(hù)索引集合就要做相應(yīng)的更新工作。
2、在海量查詢時(shí)盡量少用格式轉(zhuǎn)換。
3、ORDER BY和GROPU BY:使用ORDER BY和GROUP BY短語,任何一種索引都有助于SELECT的性能提高。
4、任何對(duì)列的操作都將導(dǎo)致表掃描,它包括數(shù)據(jù)庫教程函數(shù)、計(jì)算表達(dá)式等等,查詢時(shí)要盡可能將操作移至等號(hào)右邊。
5、IN、OR子句常會(huì)使用工作表,使索引失效。如果不產(chǎn)生大量重復(fù)值,可以考慮把子句拆開。拆開的子句中應(yīng)該包含索引。
6、只要能滿足你的需求,應(yīng)盡可能使用更小的數(shù)據(jù)類型:例如使用MEDIUMINT代替INT
7、盡量把所有的列設(shè)置為NOT NULL,如果你要保存NULL,手動(dòng)去設(shè)置它,而不是把它設(shè)為默認(rèn)值。
8、盡量少用VARCHAR、TEXT、BLOB類型
9、如果你的數(shù)據(jù)只有你所知的少量的幾個(gè)。最好使用ENUM類型
10、正如graymice所講的那樣,建立索引。
?
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
LIMIT子句可以被用于強(qiáng)制SELECT語句返回指定的記錄數(shù)。LIMIT接受一個(gè)或兩個(gè)數(shù)字參數(shù),參數(shù)必須是一個(gè)整數(shù)常量。
如果給定兩個(gè)參數(shù),第一個(gè)參數(shù)指定第一個(gè)返回記錄行的偏移量,第二個(gè)參數(shù)指定返回記錄行的最大數(shù)目。
初始記錄行的偏移量是0(而不是1):為了與 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。
mysql> SELECT * FROM table LIMIT 5, 10;? // 檢索記錄行 6-15
//為了檢索從某一個(gè)偏移量到記錄集的結(jié)束所有的記錄行,可以指定第二個(gè)參數(shù)為 -1:
mysql> SELECT * FROM table LIMIT 95, -1; // 檢索記錄行 96-last.
//如果只給定一個(gè)參數(shù),它表示返回最大的記錄行數(shù)目:
mysql> SELECT * FROM table LIMIT 5;????? //檢索前 5 個(gè)記錄行
//換句話說,LIMIT n 等價(jià)于 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條記錄,取其中最大一個(gè)id值作為起始標(biāo)識(shí),然后利用它可以快速定位下100條記錄
第2句擇是僅僅取90000條記錄后1條,然后取id值作起始標(biāo)識(shí)定位下100條記錄
第1句執(zhí)行結(jié)果.100 rows in set (0.23) sec
第2句執(zhí)行結(jié)果.100 rows in set (0.19) sec
很明顯第2句勝出.看來limit好像并不完全像我之前想象的那樣做全表掃描返回limit offset+length條記錄,
這樣看來limit比起MS-SQL的Top性能還是要提高不少的.
其實(shí)sql-2完全可以簡(jiǎn)化成:
SELECT * FROM table WHERE id >= (
??? SELECT id FROM table limit 90000, 1
) limit 100;
直接利用第90000條記錄的id,不用經(jīng)過MAX函數(shù)運(yùn)算,這樣做理論上效率因該高一些,但在實(shí)際使用中幾乎看不到效果,
因?yàn)楸旧矶ㄎ籭d返回的就是1條記錄,MAX幾乎不用運(yùn)作就能得到結(jié)果,但這樣寫更清淅明朗,省去了畫蛇那一足.
可是,既然MySQL有l(wèi)imit可以直接控制取出記錄的位置,為什么不干脆用SELECT id FROM table limit 90000, 1呢?豈不更簡(jiǎn)潔?
?
tmp_table_size = 500mb //臨時(shí)表大小設(shè)置
//指定用于索引的緩沖區(qū)大小,增加它可得到更好的索引處理性能。
//對(duì)于內(nèi)存在4GB左右的服務(wù)器該參數(shù)可設(shè)置為256M或384M。
//注意:該參數(shù)值設(shè)置的過大反而會(huì)是服務(wù)器整體效率降低!
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狀態(tài)
PORT=`netstat -na | grep "LISTEN" | grep "3306" | awk '{print $4}' | awk -F. '{print $2}'`
if [ "$PORT" -eq "3306" ]
??????? then
#######檢查mysql占CPU負(fù)載
??????? mysql_cpu=`top -U root -b -n 1 | grep mysql | awk '{print $10}'|awk -F. '{print $1}'`
##如果mysql cpu負(fù)載大于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
?>
影響列數(shù): 4999 (查詢花費(fèi) 0.1756 秒)
UPDATE `jobs_faces` SET postime = '1250784000' WHERE jid <505000 AND jid >500000
jobs_faces字段
字段 類型 整理 屬性 Null 默認(rèn) 額外 操作
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? 否
影響列數(shù): 4999 (查詢花費(fèi) 0.2393 秒)
UPDATE `jobs_faces` SET postime = '1250784000' WHERE jid <455000 AND jid >450000
注意:要把php.ini中 extension=php_mbstring.dll 前的;號(hào)去掉,重啟apache就可以了。
我創(chuàng)建三個(gè)文件: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 />';
?>
1. 下載PostgreSQL數(shù)據(jù)庫zip版本
2.? 解壓到D盤,例如:D:\database\postgresql
3.? cmd窗口進(jìn)入D:\database\postgresq\bin,依次執(zhí)行如下命令:
set PGHOME=D:\database\postgresq
set PGDATA=%PGHOME%\data
set PGLIB=%PGHOME%\lib
set PGHOST=localhost
set PATH=%PGHOME%\bin;%PATH%

4.? 添加用戶
> 添加windows用戶,用于啟動(dòng)PostgreSQL的windows服務(wù)
D:\database\postgresql>net user postgres pgsqlpw /add /expires:never /passwordchg:no
> 為保證安全,此用戶不允許本地登錄
D:\database\postgresql>net localgroup users postgres /del
> 賦于windows用戶postgres訪問PostgreSQL安裝目錄的權(quán)限
D:\database\postgresql>cacls . /T /E /P postgres:R
5.? 初始化數(shù)據(jù)庫
> 切換到windows用戶postgres的命令行環(huán)境
D:\database\postgresql>runas /noprofile /env /user:postgres "cmd"
> 初始化數(shù)據(jù)庫,若不使用-U admin,則數(shù)據(jù)庫里自動(dòng)添加當(dāng)前windows用戶(即postgres)為數(shù)據(jù)庫帳號(hào)
D:\database\postgresql>bin\initdb -D "D:\database\postgresql\data" -E UTF-8? --locale=chs -A md5 -U admin -W

6. 啟動(dòng)PostgreSQL服務(wù):
pg_ctl -D?D:\database\postgresql\data -l? D:\database\postgresql\pglog.txt start



7. 創(chuàng)建并連接數(shù)據(jù)庫:
createdb test
psql -h localhost -w -d test

8. 關(guān)閉PostgreSQL服務(wù):
pg_ctl -D? D:\database\postgresql\data stop
9. 注冊(cè)為Windows服務(wù):
> 注冊(cè)為windows服務(wù),當(dāng)前windows用戶(即postgres)將作為PostgreSQL服務(wù)的登錄用戶
D:\pgsql>bin\pg_ctl register -N PostgreSQL? -D “D:\database\postgresql\data”
> 啟動(dòng)PostgreSQL服務(wù)
D:\pgsql> sc start PostgreSQL
?
?
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,當(dāng)然還有uuid_generate_v3和uuid_generate_v5。
其他使用可以參見PostgreSQL官方文檔?http://www.postgresql.org/docs/8.3/static/uuid-ossp.html
> memcache介紹
Memcached是一個(gè)高性能的分布式內(nèi)存對(duì)象緩存系統(tǒng),用于動(dòng)態(tài)Web應(yīng)用以減輕數(shù)據(jù)庫負(fù)載。它通過在內(nèi)存中緩存數(shù)據(jù)和對(duì)象來減少讀取數(shù)據(jù)庫的次數(shù),從而提供動(dòng)態(tài)、數(shù)據(jù)庫驅(qū)動(dòng)網(wǎng)站的速度。Memcached基于一個(gè)存儲(chǔ)鍵/值對(duì)的hashmap。其守護(hù)進(jìn)程(daemon )是用C寫的,但是客戶端可以用任何語言來編寫,并通過memcached協(xié)議與守護(hù)進(jìn)程通信。但是它并不提供冗余(例如,復(fù)制其hashmap條目);當(dāng)某個(gè)服務(wù)器S停止運(yùn)行或崩潰了,所有存放在S上的鍵/值對(duì)都將丟失。
Memcached官方:http://danga.com/memcached/
> memcache下載安裝
下載Windows的Server端,下載地址:http://code.jellycan.com/memcached/
安裝Memcache Server(也可以不安裝直接啟動(dòng))
1. 下載memcached的windows穩(wěn)定版,解壓放某個(gè)盤下面,比如在c:\memcached
2. 在CMD下輸入 "c:\memcached\memcached.exe -d install" 安裝.
3. 再輸入:"c:\memcached\memcached.exe -d start" 啟動(dòng)。NOTE: 以后memcached將作為windows的一個(gè)服務(wù)每次開機(jī)時(shí)自動(dòng)啟動(dòng)。這樣服務(wù)器端已經(jīng)安裝完畢了。
如果下載的是二進(jìn)制的版本,直接運(yùn)行就可以了,可以加上參數(shù)來加以設(shè)置。
常用設(shè)置:
-p <num>????????? 監(jiān)聽的端口
-l <ip_addr>????? 連接的IP地址, 默認(rèn)是本機(jī)
-d start????????? 啟動(dòng)memcached服務(wù)
-d restart??????? 重起memcached服務(wù)
-d stop|shutdown? 關(guān)閉正在運(yùn)行的memcached服務(wù)
-d install??????? 安裝memcached服務(wù)
-d uninstall????? 卸載memcached服務(wù)
-u <username>???? 以<username>的身份運(yùn)行 (僅在以root運(yùn)行的時(shí)候有效)
-m <num>????????? 最大內(nèi)存使用,單位MB。默認(rèn)64MB
-M??????????????? 內(nèi)存耗盡時(shí)返回錯(cuò)誤,而不是刪除項(xiàng)
-c <num>????????? 最大同時(shí)連接數(shù),默認(rèn)是1024
-f <factor>?????? 塊大小增長(zhǎng)因子,默認(rèn)是1.25
-n <bytes>??????? 最小分配空間,key+value+flags默認(rèn)是48
-h??????????????? 顯示幫助
然后就可以用java的memcached客戶端來試一下了。
1 echo()
可以同時(shí)輸出多個(gè)字符串,可以多個(gè)參數(shù),并不需要圓括號(hào),無返回值。
2 print()
只可以同時(shí)輸出一個(gè)字符串,一個(gè)參數(shù),需要圓括號(hào),有返回值,當(dāng)其執(zhí)行失敗時(shí)返flase .??? print 的用法和C語言很像,所以會(huì)對(duì)輸出內(nèi)容里的%做特殊解釋。
$a=print('hi');
echo $a;
//----------------------------
hi 1?? //1是$a的值。
//-----------------------------
3 die();??// 和exit()區(qū)別。
有兩個(gè)功能:先輸出內(nèi)容,然后退出程序。(常用在鏈接服務(wù)器,數(shù)據(jù)庫)
mysql_connect("locahost","root","root") or die("鏈接服務(wù)器失敗!");
4 printf();??? //f指format格式化
printf("參數(shù)1",參數(shù)2):
參數(shù)1=按什么格式輸出;參數(shù)2=輸出的變量。
(%s:按字符串;%d:按整型;%b:按二進(jìn)制;%x:按16進(jìn)制;%X:按16進(jìn)制大寫輸出;%o:按八進(jìn)制; %f:按浮點(diǎn)型)
對(duì)于參數(shù)1,其格式如下:
%[ 'padding_character][-][width][.precision]type
說明:
所有轉(zhuǎn)換都以%開頭,如果想打印一個(gè)%,則必須用“%%”;
參數(shù)padding_character是可選的,用來填充變量直至指定的寬度,如:printf ("$%'a10.2f" , 43.2); //$aaaaa43.20,默認(rèn)是填充一個(gè)空格,如果指定了一個(gè)空格或0就不需要使用“'”做為前綴。對(duì)于任何其它前綴則必須指定單引號(hào)。
【-】是可選的,添加它則表明數(shù)據(jù)應(yīng)該左對(duì)齊。而不是默認(rèn)的右對(duì)齊,如上例加一個(gè)-則為:printf ("$%'a-10.2f" , 43.2); //$43.20aaaaa
whidth 表示在這里為將被替換的變量留下多少空間(按字符計(jì)算)。如上例的10(包括小數(shù)點(diǎn)).
precision則必須是一個(gè)小數(shù)點(diǎn)開始,表示小數(shù)位后面要顯示的位數(shù)。
函數(shù),返回輸出字符個(gè)數(shù),把文字格式化以后輸出,如:
printf ("$%01.2f" , 43.2); //$43.20
$表示填充的字符
0表示位數(shù)不夠在不影響原值的情況下補(bǔ)0
1表示輸出的總寬度
2表示小數(shù)位數(shù),有四舍五入
%f 是表示顯示為一個(gè)浮點(diǎn)數(shù)
格式化命令及說明:
%% 印出百分比符號(hào),不轉(zhuǎn)換。
%b 整數(shù)轉(zhuǎn)成二進(jìn)位。
%c 整數(shù)轉(zhuǎn)成對(duì)應(yīng)的 ASCII 字符。 如:printf ("$%c" , 65); // 輸出:A
%d 整數(shù)轉(zhuǎn)成十進(jìn)位。 如:printf ("$%d" , 65.53); // 輸出:65
%f 倍精確度數(shù)字轉(zhuǎn)成浮點(diǎn)數(shù)。
%o 整數(shù)轉(zhuǎn)成八進(jìn)位。
%s 整數(shù)轉(zhuǎn)成字符串。
%x 整數(shù)轉(zhuǎn)成小寫十六進(jìn)位。
%X 整數(shù)轉(zhuǎn)成大寫十六進(jìn)位
對(duì)于printf(),還可以使用帶序號(hào)并以$符號(hào)結(jié)束的參數(shù)方式來指定參數(shù)轉(zhuǎn)換的順序。如:
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指定了使用第二個(gè)參數(shù)65.55,%1$.2f則指定用第一個(gè)參數(shù)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 (小數(shù)點(diǎn)保留2位)
???? printf("%.1f",$num); //100.0 (小數(shù)點(diǎn)保留1位)
???? printf("%`#10s",$num); // #10s
???? printf("%#10s",$num); //10s
?? ?>
5 sprintf();
此并不能直接輸出,先賦給一個(gè)變量,然后再輸出變量。
<?php
$num=100.001;
$a=sprintf("%d",$num);
echo $a; //100
?>
6 print_r();
功能:只用于輸出數(shù)組。
$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();
功能: 輸出變量的內(nèi)容,類型或字符串的內(nèi)容,類型,長(zhǎng)度。常用來調(diào)試。
<?php
$a=100;
var_dump($a); //int(100)
$a=100.356;
var_dump($a); //float(100.356)
?>
8.var_export ();
返回關(guān)于傳遞給該函數(shù)的變量的結(jié)構(gòu)信息,它和 var_dump() 類似,不同的是其返回的表示是合法的 PHP 代碼。
您可以通過將函數(shù)的第二個(gè)參數(shù)設(shè)置為 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
*/
?>
mb_convert_encoding這個(gè)函數(shù)是用來轉(zhuǎn)換編碼的。原來一直對(duì)程序編碼這一概念不理解,不過現(xiàn)在好像有點(diǎn)開竅了。
不過英文一般不會(huì)存在編碼問題,只有中文數(shù)據(jù)才會(huì)有這個(gè)問題。比如你用Zend Studio或Editplus寫程序時(shí),用的是gbk編碼,如果數(shù)據(jù)需要入數(shù)據(jù)庫,而數(shù)據(jù)庫的編碼為utf8時(shí),這時(shí)就要把數(shù)據(jù)進(jìn)行編碼轉(zhuǎn)換,不然進(jìn)到數(shù)據(jù)庫就會(huì)變成亂碼。
mb_convert_encoding的用法見官方:
http://cn.php.net/manual/zh/function.mb-convert-encoding.php
做一個(gè)GBK To UTF-8
< ?php
header("content-Type: text/html; charset=Utf-8");
echo mb_convert_encoding("妳係我的友仔", "UTF-8", "GBK");
?>
再來個(gè)GB2312 To Big5
< ?php
header("content-Type: text/html; charset=big5");
echo mb_convert_encoding("你是我的朋友", "big5", "GB2312");
?>
不過要使用上面的函數(shù)需要安裝但是需要先enable mbstring 擴(kuò)展庫。
PHP中的另外一個(gè)函數(shù)iconv也是用來轉(zhuǎn)換字符串編碼的,與上函數(shù)功能相似。
下面還有一些詳細(xì)的例子:
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 擴(kuò)展庫,在 php.ini里將; extension=php_mbstring.dll 前面的 ; 去掉
mb_convert_encoding 可以指定多種輸入編碼,它會(huì)根據(jù)內(nèi)容自動(dòng)識(shí)別,但是執(zhí)行效率比iconv差太多;
string iconv ( string in_charset, string out_charset, string str )
注意:第二個(gè)參數(shù),除了可以指定要轉(zhuǎn)化到的編碼以外,還可以增加兩個(gè)后綴://TRANSLIT 和 //IGNORE,其中 //TRANSLIT
會(huì)自動(dòng)將不能直接轉(zhuǎn)化的字符變成一個(gè)或多個(gè)近似的字符,//IGNORE 會(huì)忽略掉不能轉(zhuǎn)化的字符,而默認(rèn)效果是從第一個(gè)非法字符截?cái)唷?/span>
Returns the converted string or FALSE on failure.
使用:
發(fā)現(xiàn)iconv在轉(zhuǎn)換字符”—”到gb2312時(shí)會(huì)出錯(cuò),如果沒有ignore參數(shù),所有該字符后面的字符串都無法被保存。不管怎么樣,這個(gè)”—”都無法轉(zhuǎn)換成功,無法輸出。 另外mb_convert_encoding沒有這個(gè)bug.
一般情況下用 iconv,只有當(dāng)遇到無法確定原編碼是何種編碼,或者iconv轉(zhuǎn)化后無法正常顯示時(shí)才用mb_convert_encoding 函數(shù).
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”);
選擇【W(wǎng)indow】菜單
Preferences ——>General——>Editors——>Text Editors——>Hyperlinking
<?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());
??????????????? }
??????? }
}
?>
今天在MySQL中建立了一張表,其中一個(gè)字段是order,通過jdbc往里面插數(shù)據(jù)一直報(bào)錯(cuò),好長(zhǎng)時(shí)間找不到原因
結(jié)果把order字段的名稱改成別的,居然成功插入數(shù)據(jù),看來是MySQL字段列名不能使用insert、order等關(guān)鍵字
> 添加curl擴(kuò)展
1.在C\windows里的php.ini中我打開了extension=php_curl.dll的功能
2.把php目錄中的libeay32.dll,ssleay32.dll拷到c:\windows\system32里
3.重新啟動(dòng)Apache
> 代碼
<?php
?? //初始化curl
?? $ch = curl_init() or die (curl_error());
?? echo "Test for searching 'php' in baidu.";
?? //設(shè)置URL參數(shù)
?? curl_setopt($ch,CURLOPT_URL,"http://www.baidu.com/s?wd=php");
?? //要求CURL返回?cái)?shù)據(jù)
?? curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
?? //執(zhí)行請(qǐng)求
?? $result = curl_exec($ch) or die (curl_error());
?? //取得返回的結(jié)果,并顯示
?? echo $result;
?? echo curl_error($ch);
?? //關(guān)閉CURL
?? curl_close($ch);
?>
> 效果

>CURL函數(shù)庫(Client URL Library Function)
curl_close — 關(guān)閉一個(gè)curl會(huì)話
curl_copy_handle — 拷貝一個(gè)curl連接資源的所有內(nèi)容和參數(shù)
curl_errno — 返回一個(gè)包含當(dāng)前會(huì)話錯(cuò)誤信息的數(shù)字編號(hào)
curl_error — 返回一個(gè)包含當(dāng)前會(huì)話錯(cuò)誤信息的字符串
curl_exec — 執(zhí)行一個(gè)curl會(huì)話
curl_getinfo — 獲取一個(gè)curl連接資源句柄的信息
curl_init — 初始化一個(gè)curl會(huì)話
curl_multi_add_handle — 向curl批處理會(huì)話中添加單獨(dú)的curl句柄資源
curl_multi_close — 關(guān)閉一個(gè)批處理句柄資源
curl_multi_exec — 解析一個(gè)curl批處理句柄
curl_multi_getcontent — 返回獲取的輸出的文本流
curl_multi_info_read — 獲取當(dāng)前解析的curl的相關(guān)傳輸信息
curl_multi_init — 初始化一個(gè)curl批處理句柄資源
curl_multi_remove_handle — 移除curl批處理句柄資源中的某個(gè)句柄資源
curl_multi_select — Get all the sockets associated with the cURL extension, which can then be "selected"
curl_setopt_array — 以數(shù)組的形式為一個(gè)curl設(shè)置會(huì)話參數(shù)
curl_setopt — 為一個(gè)curl設(shè)置會(huì)話參數(shù)
curl_version — 獲取curl相關(guān)的版本信息
關(guān)鍵詞:php抓取 ? php庫函數(shù)?? curl?? php常用函數(shù)
> 函數(shù)date(format,timestamp)
format???????? 必需。規(guī)定時(shí)間戳的格式。
timestamp????? 可選。規(guī)定時(shí)間戳。默認(rèn)是當(dāng)前的日期和時(shí)間。
<?php
echo date("Y/m/d");
echo "<br />";
echo date("Y.m.d");
echo "<br />";
echo date("Y-m-d");
?>
> 格式化當(dāng)前時(shí)間
<?php echo $showtime=date("Y-m-d H:i:s");?>
顯示的格式: 年-月-日 小時(shí):分鐘:妙
相關(guān)時(shí)間參數(shù):
a - "am" 或是 "pm"
A - "AM" 或是 "PM"
d - 幾日,二位數(shù)字,若不足二位則前面補(bǔ)零; 如: "01" 至 "31"
D - 星期幾,三個(gè)英文字母; 如: "Fri"
F - 月份,英文全名; 如: "January"
h - 12 小時(shí)制的小時(shí); 如: "01" 至 "12"
H - 24 小時(shí)制的小時(shí); 如: "00" 至 "23"
g - 12 小時(shí)制的小時(shí),不足二位不補(bǔ)零; 如: "1" 至 12"
G - 24 小時(shí)制的小時(shí),不足二位不補(bǔ)零; 如: "0" 至 "23"
i - 分鐘; 如: "00" 至 "59"
j - 幾日,二位數(shù)字,若不足二位不補(bǔ)零; 如: "1" 至 "31"
l - 星期幾,英文全名; 如: "Friday"
m - 月份,二位數(shù)字,若不足二位則在前面補(bǔ)零; 如: "01" 至 "12"
n - 月份,二位數(shù)字,若不足二位則不補(bǔ)零; 如: "1" 至 "12"
M - 月份,三個(gè)英文字母; 如: "Jan"
s - 秒; 如: "00" 至 "59"
S - 字尾加英文序數(shù),二個(gè)英文字母; 如: "th","nd"
t - 指定月份的天數(shù); 如: "28" 至 "31"
U - 總秒數(shù)
w - 數(shù)字型的星期幾,如: "0" (星期日) 至 "6" (星期六)
Y - 年,四位數(shù)字; 如: "1999"
y - 年,二位數(shù)字; 如: "99"
z - 一年中的第幾天; 如: "0" 至 "365"
?
關(guān)鍵詞: php學(xué)習(xí)?? php教程? php格式化時(shí)間?? php函數(shù)? date()
?
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 // 設(shè)置為On后,即使捕捉到異常,代碼行仍將強(qiáng)制執(zhí)行異常跟蹤.
xdebug.show_local_vars = 1??? // 將打印每個(gè)函數(shù)調(diào)用的最外圍中的所有局部變量,包括尚未初始化的變量
xdebug.max_nesting_level = 50
xdebug.var_display_max_depth = 6 // 表示轉(zhuǎn)儲(chǔ)復(fù)雜變量的深度.
xdebug.dump_once = On
xdebug.dump_globals = On
// 如果進(jìn)一步將 xdebug.dump_undefined 設(shè)為 On 并且不設(shè)定指定的超全局變量,則仍用值 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? 設(shè)為 0則輸出將符合人類閱讀習(xí)慣(將參數(shù)設(shè)為 1 則為機(jī)器可讀格式).
xdebug.show_mem_delta = 1 則可以查看內(nèi)存使用量是在增加還是在減少,????
xdebug.collect_params = 4 則可以查看傳入?yún)?shù)的類型和值.要監(jiān)視每個(gè)函數(shù)返回的值,請(qǐng)?jiān)O(shè)定 xdebug.collect_return = 1.
PHP Warning:? Xdebug MUST be loaded as a Zend extension in Unknown on line 0?出錯(cuò)解決
;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"
?
比如當(dāng)前文件是放在(d:\www\)下,文件名是test.php。
<?php?? echo __FILE__ ; // 取得當(dāng)前文件的絕對(duì)地址,結(jié)果:D:\www\test.php?? echo dirname(__FILE__); // 取得當(dāng)前文件所在的絕對(duì)目錄,結(jié)果:D:\www\?? echo dirname(dirname(__FILE__)); //取得當(dāng)前文件的上一層目錄名,結(jié)果:D:\?>
使用方法提示,
dirname(__FILE__) 取到的是當(dāng)前文件的絕對(duì)路徑,也就是說,比起相對(duì)路徑,查找速度是最快的。
如果重復(fù)一次可以把目錄往上提升一個(gè)層次:
比如:$d = dirname(dirname(__FILE__));
其實(shí)就是把一個(gè)目錄給dirname()做參數(shù)了.因?yàn)閐irname()返回最后的目錄不帶\\或者是/
所以重復(fù)使用的時(shí)候可以認(rèn)為 dirname() 把最下層的目錄當(dāng)成文件名來處理了.照常返回
當(dāng)前目錄的上級(jí)目錄.這樣重復(fù)就得到了它的上一級(jí)的目錄.
包含得到上一級(jí)目錄的文件
include(dirname(__FILE__).’/../filename.php’);
本文主要介紹PHP5.2.11 + Apache2.2.19 + MySQL5.1.45的PHP集成運(yùn)行環(huán)境的搭建(Windows XP SP3操作系統(tǒng)環(huán)境)
> 安裝并配置APACHE(安裝到C:\apache)
?? 1、安裝時(shí)默認(rèn)安裝,Network Domain, Server Name 我填寫我的計(jì)算機(jī)名,Administrator's Email Address區(qū)域填你的郵件地址
?? 2、安裝完后在安裝目錄下有個(gè)conf文件夾,打開httpd.conf文件進(jìn)行配置
??????? ·找到 DocumentRoot ,將其設(shè)置為你所要存放php, htm等網(wǎng)頁文件的文件夾,如 "D:\phpapache\Apache2.2\htdocs";
??????? ·找到 DirectoryIndex ,在index.html后添加index.php, index.htm等,以單個(gè)空格將其分開;
??????? ·重啟Apache,用http://localhost或http://127.0.0.1或http://yourcompanyname測(cè)試是否成功。成功的話屏幕會(huì)有個(gè)It works!
> 安裝配置PHP(解壓PHP壓縮包到C:\php)
?? 1、將php.ini-recommended文件重命名為php.ini并將其剪到系統(tǒng)所在目錄下(如放在2000/NT的WINNT, XP的Windows目錄下),
?? 2、將extension_dir 改為php/ext所在目錄,如 "C:\php\ext";
?? 3、將doc_root 改為第一步中的同樣目錄,如 "C:\apache\htdocs";
?? 4、找到 ;session.save_path = "/tmp" ,將';'去掉,設(shè)置你保存session的目錄,如session.save_path = "C:/php/tmp";
?? 5、然后把下面幾句前面的分號(hào)去掉,以更好支持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程序作為模塊來運(yùn)行:
?????????? 打開httpd.conf,添加下面內(nèi)容(位置任意):
???????????? LoadModule php5_module "C:/php/php5apache2_2.dll"
???????????? AddType application/x-httpd-php .php
???????????? AddType application/x-httpd-php .htm
??????????? (.htm, .php為可執(zhí)行php語言的擴(kuò)展名,也可加html, php3, php4,甚至txt)
?????????? (以下兩步可以不需要)
?? 2、如果你出于某種原因而需要在CGI模式中運(yùn)行PHP程序(使用Php.exe),
????????? 請(qǐng)將上面這一行變成注釋(各行頭加#即可),添加下面這些行:
?????????? # ScriptAlias /php/ "C:/php/"
?????????? # AddType application/x-httpd-php .php
?????????? #Action application/x-httpd-php "/php/php-cgi.exe"
?? 3、現(xiàn)在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"
> 重啟服務(wù),測(cè)試環(huán)境
?? 1、在C:\php里找到php5ts.dll,libmysql.dll將其復(fù)制到C:\winnt\system32下(winNT/2000的機(jī)器),而winXP/2003是復(fù)制到C:\windows\system32下
?? 2、測(cè)試Apache與php是否連接成功:
????????? 啟動(dòng)start apache服務(wù)或者正在運(yùn)行的就重新啟動(dòng)restart apache
?? 3、在Web根目錄下新建test.php(即C:\apache\htdocs目下)
?????????? <html>
?????????? <head><title>test</title></head>
?????????? <body>
??????????? <?php
????????????? phpinfo();
??????????? ?>
???????? </body>
????????? </html>
?? 4、運(yùn)行http://localhost/test.php
???????? 如果成功,則應(yīng)該看到一個(gè)含有PHP徽標(biāo)的網(wǎng)頁,其中包含大量設(shè)置和其他信息
???????? 那么恭喜你,環(huán)境已經(jīng)搭建成功!
?
關(guān)鍵詞:PHP?? PHP5? Apache? MySQL? PHP運(yùn)行環(huán)境?
Hibernate 團(tuán)隊(duì)對(duì)外宣布了一個(gè)新的家族成員,Hibernate OGM, OGM 是 Object Grid Mapping的縮寫,它的目標(biāo)是試圖使用 JPA 來操作 NoSQL數(shù)據(jù)庫,目前似乎局限于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
參考手冊(cè):http://docs.jboss.org/hibernate/ogm/3.0/reference/en-US/html_single/
PS:從目前情況看,不支持流行的 MongoDB 等等。與DataNucleus(http://www.datanucleus.org)在Backend的存儲(chǔ)技術(shù)方面,還不能相提并論,DataNucleus支持JDO,JPA標(biāo)準(zhǔn),支持目前幾乎所有的流行的存儲(chǔ)方式,Google的APPEngine也是基于DataNucleus的。
”…在很多領(lǐng)域,專家的作用體現(xiàn)在他們的專業(yè)知識(shí)上而不是智力上。“
--Don Reinertsen
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain Driven Design)是一種軟件開發(fā)方法,目的是讓軟件系統(tǒng)在實(shí)現(xiàn)時(shí)準(zhǔn)確的基于對(duì)真實(shí)業(yè)務(wù)過程的建模并根據(jù)真實(shí)業(yè)務(wù)過程的調(diào)整而調(diào)整。
傳統(tǒng)的開發(fā)工作趨向于一種以技術(shù)為先導(dǎo)的過程,需求從業(yè)務(wù)方傳遞到開發(fā)團(tuán)隊(duì),開發(fā)人員依據(jù)需求上的描述創(chuàng)造出最有可能的假想。
在瀑布開發(fā)過程中,這導(dǎo)致了大量的需要頻繁校對(duì),分析,復(fù)核和審批的需求文檔。之后這些文檔被交給開發(fā)團(tuán)隊(duì)去變成能夠運(yùn)行的軟件。
敏捷開發(fā)方法同樣可以采納瀑布模式過程中產(chǎn)生的需求文檔,但敏捷方法在實(shí)際的處理過程中會(huì)把它們分成很小的任務(wù)和“故事”,之后的開發(fā)工作將依據(jù)這些任務(wù)的排序。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)很大程度上使你從這兩種截然不同的結(jié)果中抽身出來,讓你能看到需求是如何在第一現(xiàn)場(chǎng)被收集到——如果你愿意看的話,它在動(dòng)手先做的方式和在最后一分鐘才做的方式之間做了彌補(bǔ)。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)方式知道需求是永遠(yuǎn)不會(huì)“完成”的,需求就像一個(gè)活的文檔。更重要的是,這些仍待討論的活文檔實(shí)際上就是軟件自身——所有的文檔都是程序代碼的一種影像,一種演示品。
隨著軟件系統(tǒng)的開發(fā)和發(fā)展,你對(duì)各種問題的理解也會(huì)更深——領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)就是要通過深入的理解問題來找到問題的解決方案。
然而,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)真正的不同之處卻是,它把軟件系統(tǒng)當(dāng)作業(yè)務(wù)過程的一個(gè)影射,是使能動(dòng),而不是驅(qū)動(dòng)。領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)是要你深入到業(yè)務(wù)過程中,了解業(yè)務(wù)術(shù)語和實(shí)踐方法。技術(shù)方面的事被放在了第二位,只是最終的一種手段而已。
Ubiquitous語言(UL)是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的中心——這是一種共有的不斷成長(zhǎng)的語言。它是一種來源于業(yè)務(wù)術(shù)語、經(jīng)過開發(fā)團(tuán)隊(duì)的補(bǔ)充而產(chǎn)生
的協(xié)商后的語言。如果一個(gè)業(yè)務(wù)人員不懂得UL里的一個(gè)術(shù)語,有可能是UL需要改進(jìn)發(fā)展。如果一個(gè)技術(shù)人員不懂得UL里的一個(gè)術(shù)語,有可能是他們需要跟領(lǐng)域
專家進(jìn)行交流。
領(lǐng)域?qū)<沂穷I(lǐng)域驅(qū)動(dòng)設(shè)計(jì)里第二重要的組成部分——這些人能夠?qū)@個(gè)領(lǐng)域有深入的了解,包括這個(gè)業(yè)務(wù)本身。這些人構(gòu)成了開發(fā)過程中必要的組成部
分。他們也許像一些敏捷開發(fā)方法里傳統(tǒng)的產(chǎn)品擁有者那樣不需要“全天候”的在職,但他們必須在開發(fā)過程中能被持續(xù)的接觸到,而且隨時(shí)準(zhǔn)備好參與到開發(fā)過程
中。領(lǐng)域?qū)<也荒鼙划?dāng)作門外人,而應(yīng)被當(dāng)作領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)過程中的核心——他們非常像是開發(fā)團(tuán)隊(duì)中的一部分,就像普通的開發(fā)者和測(cè)試者一樣。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)沒有開始和結(jié)束——它是一個(gè)不斷的再評(píng)估,再重構(gòu),再建模,再設(shè)計(jì)的持續(xù)過程——每一次的對(duì)話都會(huì)使你對(duì)問題有更進(jìn)一步的理解。領(lǐng)
域驅(qū)動(dòng)設(shè)計(jì)沒有“完成”點(diǎn)——它永遠(yuǎn)都在進(jìn)行;Ubiquitous語言會(huì)不斷發(fā)展和成長(zhǎng),領(lǐng)域模型隨著對(duì)業(yè)務(wù)理解的改變而改變,代碼不斷的再組織和重構(gòu)
來更好的表現(xiàn)你的理解。
各種模擬產(chǎn)物產(chǎn)生又拋棄,而唯一真正有意義的只有代碼。它是解決方案的唯一表達(dá),是一種不再抽象的表達(dá)。文檔是用來解釋和描述系統(tǒng)的,而只有代
碼能不失分毫的做到這些。這就是說,在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)里,代碼必須保持高質(zhì)量,要清晰,要有表達(dá)力,沒有技術(shù)上省略和專門用語,盡可能的要讓代碼能夠在被解
釋時(shí)對(duì)領(lǐng)域?qū)<矣行┮饬x。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)里沒有精巧的代碼,也沒有奇特的處理過程,或“你不需要知道”的模塊。領(lǐng)域?qū)<也恍枰蔀殚_發(fā)人員來理解軟件系統(tǒng)里用來做這些工作的關(guān)鍵部分是什么。他們同樣也不需要考慮數(shù)據(jù)庫或批處理任務(wù)或其他技術(shù)相關(guān)的方面。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)是敏捷方法的終極表達(dá)——它是用來處理不斷變化和發(fā)展的需求的——正如任何一個(gè)從未涉足軟件項(xiàng)目的人都知道——一個(gè)項(xiàng)目的需求從開始到結(jié)束保持一成不變是極其罕見的,絕大多數(shù)情況是它會(huì)隨著業(yè)務(wù)的增長(zhǎng)和變化而變化。
通過不斷的交流,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)會(huì)指導(dǎo)你用軟件最精確的表達(dá)你的業(yè)務(wù)過程。
?
關(guān)鍵詞:領(lǐng)域模型???? 設(shè)計(jì)???? 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)