posts - 495,  comments - 11,  trackbacks - 0
  2011年5月27日

> 引言
  在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 阅读(1490) | 评论 (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 阅读(1288) | 评论 (0)编辑 收藏
关系数据库不支持继承,我们可以做如下的映射,这些映射都是牺牲关系模式的范式基础的
 
1,  用一个表包含所有继承层次的所有字段,然后标识列来标示是哪个类。这种映射方法最简单,但是是违反规范化的,而且有些字段要强制为NULL值,无法保证关系数据模型的数据完整性,这种映射方式性能最高,最简单。
 
2,  每个具体类一张表(意思就是父类不需要表),所有父属性在具体类表中重复,这种映射如果要查询父类要全部扫描子类表,而且一旦父类变化,这些字表要全部变化。
 
3,  每个类一张表,表里只包含所属类的属性,然后子类和父类共享外键,这种映射避免了第2种的可怕的修改,但是查询的时候要执行连接。
posted @ 2011-09-27 09:38 jadmin 阅读(197) | 评论 (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 阅读(987) | 评论 (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 阅读(1000) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2011-09-23 16:17 jadmin 阅读(1270) | 评论 (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 阅读(193) | 评论 (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 阅读(1214) | 评论 (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 阅读(1407) | 评论 (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 阅读(256) | 评论 (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 阅读(105) | 评论 (0)编辑 收藏

SymmetricDS是一个平台独立的数据同步和复制的解决方案。

配置数据模型:

运行时数据模型:

posted @ 2011-09-02 09:15 jadmin 阅读(231) | 评论 (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 阅读(137) | 评论 (0)编辑 收藏

lazy的属性有false、true、extra

false和true用得比较多,extra属性是不大容易重视的,其实它和true差不多

extra有个小的智能的地方是,即调用集合的size/contains等方法的时候,hibernate并不会去加载整个集合的数据,而是发出一条聪明的SQL语句,以便获得需要的值,只有在真正需要用到这些集合元素对象数据的时候,才去发出查询语句加载所有对象的数据


posted @ 2011-08-30 20:00 jadmin 阅读(107) | 评论 (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 阅读(125) | 评论 (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 阅读(128) | 评论 (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 阅读(98) | 评论 (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 阅读(424) | 评论 (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 阅读(216) | 评论 (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 阅读(106) | 评论 (0)编辑 收藏

今天启动Eclipse时,弹出错误提示:

解决办法:将Eclipse下的eclipse.ini文件做如下改动

=>

 

posted @ 2011-08-16 17:09 jadmin 阅读(105) | 评论 (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 阅读(115) | 评论 (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 阅读(116) | 评论 (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 阅读(115) | 评论 (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 阅读(160) | 评论 (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 阅读(230) | 评论 (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 阅读(586) | 评论 (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 阅读(92) | 评论 (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 阅读(78) | 评论 (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 阅读(96) | 评论 (0)编辑 收藏

选择【Window】菜单
Preferences ——>General——>Editors——>Text Editors——>Hyperlinking



posted @ 2011-07-22 10:17 jadmin 阅读(179) | 评论 (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 阅读(104) | 评论 (0)编辑 收藏

今天在MySQL中建立了一张表,其中一个字段是order,通过jdbc往里面插数据一直报错,好长时间找不到原因

结果把order字段的名称改成别的,居然成功插入数据,看来是MySQL字段列名不能使用insert、order等关键字


posted @ 2011-07-12 20:40 jadmin 阅读(101) | 评论 (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 阅读(109) | 评论 (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 阅读(106) | 评论 (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 阅读(136) | 评论 (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 阅读(94) | 评论 (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 阅读(80) | 评论 (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 阅读(147) | 评论 (0)编辑 收藏

  ”…在很多领域,专家的作用体现在他们的专业知识上而不是智力上。“

  --Don Reinertsen

  领域驱动设计(Domain Driven Design)是一种软件开发方法,目的是让软件系统在实现时准确的基于对真实业务过程的建模并根据真实业务过程的调整而调整。

  传统的开发工作趋向于一种以技术为先导的过程,需求从业务方传递到开发团队,开发人员依据需求上的描述创造出最有可能的假想。

  在瀑布开发过程中,这导致了大量的需要频繁校对,分析,复核和审批的需求文档。之后这些文档被交给开发团队去变成能够运行的软件。

  敏捷开发方法同样可以采纳瀑布模式过程中产生的需求文档,但敏捷方法在实际的处理过程中会把它们分成很小的任务和“故事”,之后的开发工作将依据这些任务的排序。

  领域驱动设计很大程度上使你从这两种截然不同的结果中抽身出来,让你能看到需求是如何在第一现场被收集到——如果你愿意看的话,它在动手先做的方式和在最后一分钟才做的方式之间做了弥补。

  领域驱动设计方式知道需求是永远不会“完成”的,需求就像一个活的文档。更重要的是,这些仍待讨论的活文档实际上就是软件自身——所有的文档都是程序代码的一种影像,一种演示品。

  随着软件系统的开发和发展,你对各种问题的理解也会更深——领域驱动设计就是要通过深入的理解问题来找到问题的解决方案。

  然而,领域驱动设计真正的不同之处却是,它把软件系统当作业务过程的一个影射,是使能动,而不是驱动。领域驱动设计是要你深入到业务过程中,了解业务术语和实践方法。技术方面的事被放在了第二位,只是最终的一种手段而已。

  Ubiquitous语言(UL)是领域驱动设计的中心——这是一种共有的不断成长的语言。它是一种来源于业务术语、经过开发团队的补充而产生 的协商后的语言。如果一个业务人员不懂得UL里的一个术语,有可能是UL需要改进发展。如果一个技术人员不懂得UL里的一个术语,有可能是他们需要跟领域 专家进行交流。

  领域专家是领域驱动设计里第二重要的组成部分——这些人能够对这个领域有深入的了解,包括这个业务本身。这些人构成了开发过程中必要的组成部 分。他们也许像一些敏捷开发方法里传统的产品拥有者那样不需要“全天候”的在职,但他们必须在开发过程中能被持续的接触到,而且随时准备好参与到开发过程 中。领域专家不能被当作门外人,而应被当作领域驱动设计过程中的核心——他们非常像是开发团队中的一部分,就像普通的开发者和测试者一样。

  领域驱动设计没有开始和结束——它是一个不断的再评估,再重构,再建模,再设计的持续过程——每一次的对话都会使你对问题有更进一步的理解。领 域驱动设计没有“完成”点——它永远都在进行;Ubiquitous语言会不断发展和成长,领域模型随着对业务理解的改变而改变,代码不断的再组织和重构 来更好的表现你的理解。

  各种模拟产物产生又抛弃,而唯一真正有意义的只有代码。它是解决方案的唯一表达,是一种不再抽象的表达。文档是用来解释和描述系统的,而只有代 码能不失分毫的做到这些。这就是说,在领域驱动设计里,代码必须保持高质量,要清晰,要有表达力,没有技术上省略和专门用语,尽可能的要让代码能够在被解 释时对领域专家有些意义。

  领域驱动设计里没有精巧的代码,也没有奇特的处理过程,或“你不需要知道”的模块。领域专家不需要成为开发人员来理解软件系统里用来做这些工作的关键部分是什么。他们同样也不需要考虑数据库或批处理任务或其他技术相关的方面。

  领域驱动设计是敏捷方法的终极表达——它是用来处理不断变化和发展的需求的——正如任何一个从未涉足软件项目的人都知道——一个项目的需求从开始到结束保持一成不变是极其罕见的,绝大多数情况是它会随着业务的增长和变化而变化。

  通过不断的交流,领域驱动设计会指导你用软件最精确的表达你的业务过程。

 

关键词:领域模型     设计     领域驱动设计

posted @ 2011-06-11 02:26 jadmin 阅读(92) | 评论 (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 阅读(118) | 评论 (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 阅读(149) | 评论 (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 阅读(131) | 评论 (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 阅读(109) | 评论 (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 阅读(116) | 评论 (0)编辑 收藏

顾名思义:同步任务是指事情需要一件一件的做,做完当前的任务,才能开始做下一任务;异步任务是指做当前任务的同时,后台还可以在执行其他任务,可理解为可同时执行多任务,不必一件一件接着去做,下面开始上例子了

1.同步任务

/*
 * @(#)SyncTaskExecutorTest.java    2011-4-27
 *
 * Copyright (c) 2011. All Rights Reserved.
 *
 */

package org.jsoft.opensource.demos.spring.task;

import org.junit.Test;
import org.springframework.core.task.SyncTaskExecutor;

/**
 * Spring同步任务处理
 *
 * @author <a href="mailto:hongyuan.czq@taobao.com">Gerald Chen</a>
 * @version $Id: SyncTaskExecutorTest.java,v 1.1 2011/05/30 08:58:07 gerald.chen Exp $
 */
public class SyncTaskExecutorTest {

    @Test
    public void test() throws InterruptedException {
        SyncTaskExecutor executor = new SyncTaskExecutor();
        executor.execute(new OutThread());
        System.out.println("Hello, World!");
        Thread.sleep(10000 * 1000L);
    }
    
    static class OutThread implements Runnable {

        public void run() {
            for (int i = 0; i < 1000; i++) {
                System.out.println(i + " start ...");
                try {
                    Thread.sleep(2 * 1000L);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        
    }

}

必须在线程任务执行完毕之后,"Hello,World!"才会被打印出来

2.异步任务

 /*
 * @(#)AsyncTaskExecutorTest.java    2011-4-27
 *
 * Copyright (c) 2011. All Rights Reserved.
 *
 */

package org.jsoft.opensource.demos.spring.task;

import org.junit.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;

/**
 * Spring异步任务处理
 *
 * @author <a href="mailto:hongyuan.czq@taobao.com">Gerald Chen</a>
 * @version $Id: AsyncTaskExecutorTest.java,v 1.1 2011/05/30 08:58:07 gerald.chen Exp $
 */
public class AsyncTaskExecutorTest {

    @Test
    public void test() throws InterruptedException {
        AsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("sys.out");
        executor.execute(new OutThread(), 50000L);
        System.out.println("Hello, World!");
        Thread.sleep(10000 * 1000L);
    }
    
    static class OutThread implements Runnable {

        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(i + " start ...");
                try {
                    Thread.sleep(2 * 1000L);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        
    }
}

"Hello,World!"被正常打印出来,线程任务在后台静静地执行.

 

关键词:JAVA   Spring   任务   同步   异步    软件工程师   程序员   编程

 

posted @ 2011-06-08 20:53 jadmin 阅读(761) | 评论 (0)编辑 收藏

一、DB Shell数据库操作

数据库

1、Help查看命令提示
help
db.help();
db.yourColl.help();
db.youColl.find().help();
rs.help();

2、切换/创建数据库
>use yourDB;
当创建一个集合(table)的时候会自动创建当前数据库

3、查询所有数据库
show dbs;

4、删除当前使用数据库
db.dropDatabase();

5、从指定主机上克隆数据库
db.cloneDatabase(“127.0.0.1”);
将指定机器上的数据库的数据克隆到当前数据库

6、从指定的机器上复制指定数据库数据到某个数据库
db.copyDatabase("mydb", "temp", "127.0.0.1");
将本机的mydb的数据复制到temp数据库中

7、修复当前数据库
db.repairDatabase();

8、查看当前使用的数据库
db.getName();
db;
db和getName方法是一样的效果,都可以查询当前使用的数据库

9、显示当前db状态
db.stats();

10、当前db版本
db.version();

11、查看当前db的链接机器地址

db.getMongo();

 

Collection聚集集合

1、创建一个聚集集合(table)
db.createCollection(“collName”, {size: 20, capped: 5, max: 100});

2、得到指定名称的聚集集合(table)
db.getCollection("account");

3、得到当前db的所有聚集集合
db.getCollectionNames();

4、显示当前db所有聚集索引的状态
db.printCollectionStats();

 

用户相关

1、添加一个用户
db.addUser("name");
db.addUser("userName", "pwd123", true);
添加用户、设置密码、是否只读

2、数据库认证、安全模式
db.auth("userName", "123123");

3、显示当前所有用户
show users;

4、删除用户
db.removeUser("userName");

 

其他

1、查询之前的错误信息
db.getPrevError();

2、清除错误记录
db.resetError();

 

二、Collection聚集集合操作

查看聚集集合基本信息

1、查看帮助
db.yourColl.help();


2、查询当前集合的数据条数
db.yourColl.count();

3、查看数据空间大小
db.userInfo.dataSize();

4、得到当前聚集集合所在的db
db.userInfo.getDB();

5、得到当前聚集的状态
db.userInfo.stats();

6、得到聚集集合总大小
db.userInfo.totalSize();

7、聚集集合储存空间大小
db.userInfo.storageSize();

8、Shard版本信息
db.userInfo.getShardVersion()

9、聚集集合重命名
db.userInfo.renameCollection("users");
将userInfo重命名为users

10、删除当前聚集集合
db.userInfo.drop();

 

聚集集合查询
1、查询所有记录
db.userInfo.find();
相当于:select * from userInfo;
默认每页显示20条记录,当显示不下的情况下,可以用it迭代命令查询下一页数据。注意:键入it命令不能带“;”
但是你可以设置每页显示数据的大小,用DBQuery.shellBatchSize = 50;这样每页就显示50条记录了。

2、查询去掉后的当前聚集集合中的某列的重复数据
db.userInfo.distinct("name");
会过滤掉name中的相同数据
相当于:select distict name from userInfo;

3、查询age = 22的记录
db.userInfo.find({"age": 22});
相当于: select * from userInfo where age = 22;

4、查询age > 22的记录
db.userInfo.find({age: {$gt: 22}});
相当于:select * from userInfo where age > 22;

5、查询age < 22的记录
db.userInfo.find({age: {$lt: 22}});
相当于:select * from userInfo where age < 22;

6、查询age >= 25的记录
db.userInfo.find({age: {$gte: 25}});
相当于:select * from userInfo where age >= 25;

7、查询age <= 25的记录
db.userInfo.find({age: {$lte: 25}});

8、查询age >= 23 并且 age <= 26
db.userInfo.find({age: {$gte: 23, $lte: 26}});

9、查询name中包含 mongo的数据
db.userInfo.find({name: /mongo/});
//相当于%%
select * from userInfo where name like ‘%mongo%’;

10、查询name中以mongo开头的
db.userInfo.find({name: /^mongo/});
select * from userInfo where name like ‘mongo%’;

11、查询指定列name、age数据
db.userInfo.find({}, {name: 1, age: 1});
相当于:select name, age from userInfo;
当然name也可以用true或false,当用ture的情况下河name:1效果一样,如果用false就是排除name,显示name以外的列信息。

12、查询指定列name、age数据, age > 25
db.userInfo.find({age: {$gt: 25}}, {name: 1, age: 1});
相当于:select name, age from userInfo where age > 25;

13、按照年龄排序
升序:db.userInfo.find().sort({age: 1});
降序:db.userInfo.find().sort({age: -1});

14、查询name = zhangsan, age = 22的数据
db.userInfo.find({name: 'zhangsan', age: 22});
相当于:select * from userInfo where name = ‘zhangsan’ and age = ‘22’;

15、查询前5条数据
db.userInfo.find().limit(5);
相当于:select top 5 * from userInfo;

16、查询10条以后的数据
db.userInfo.find().skip(10);
相当于:select * from userInfo where id not in (
select top 10 * from userInfo
);

17、查询在5-10之间的数据
db.userInfo.find().limit(10).skip(5);
可用于分页,limit是pageSize,skip是第几页*pageSize

18、or与 查询
db.userInfo.find({$or: [{age: 22}, {age: 25}]});
相当于:select * from userInfo where age = 22 or age = 25;

19、查询第一条数据
db.userInfo.findOne();
相当于:select top 1 * from userInfo;
db.userInfo.find().limit(1);

20、查询某个结果集的记录条数
db.userInfo.find({age: {$gte: 25}}).count();
相当于:select count(*) from userInfo where age >= 20;

21、按照某列进行排序
db.userInfo.find({sex: {$exists: true}}).count();
相当于:select count(sex) from userInfo;

索引

1、创建索引
db.userInfo.ensureIndex({name: 1});
db.userInfo.ensureIndex({name: 1, ts: -1});

2、查询当前聚集集合所有索引
db.userInfo.getIndexes();

3、查看总索引记录大小
db.userInfo.totalIndexSize();

4、读取当前集合的所有index信息
db.users.reIndex();

5、删除指定索引
db.users.dropIndex("name_1");

6、删除所有索引索引
db.users.dropIndexes();

修改、添加、删除集合数据
1、添加
db.users.save({name: ‘zhangsan’, age: 25, sex: true});
添加的数据的数据列,没有固定,根据添加的数据为准

2、修改
db.users.update({age: 25}, {$set: {name: 'changeName'}}, false, true);
相当于:update users set name = ‘changeName’ where age = 25;

db.users.update({name: 'Lisi'}, {$inc: {age: 50}}, false, true);
相当于:update users set age = age + 50 where name = ‘Lisi’;

db.users.update({name: 'Lisi'}, {$inc: {age: 50}, $set: {name: 'hoho'}}, false, true);
相当于:update users set age = age + 50, name = ‘hoho’ where name = ‘Lisi’;

3、删除
db.users.remove({age: 132});

4、查询修改删除
db.users.findAndModify({
    query: {age: {$gte: 25}},
    sort: {age: -1},
    update: {$set: {name: 'a2'}, $inc: {age: 2}},
    remove: true
});

db.runCommand({ findandmodify : "users",
    query: {age: {$gte: 25}},
    sort: {age: -1},
    update: {$set: {name: 'a2'}, $inc: {age: 2}},
    remove: true
});
update 或 remove 其中一个是必须的参数; 其他参数可选。

参数                                                                                              详解                                                                                        默认值
query                                                                                      查询过滤条件                                                                                       {}
sort         如果多个文档符合查询过滤条件,将以该参数指定的排列方式选择出排在首位的对象,该对象将被操作           {}
remove                                                             若为true,被选中对象将在返回前被删除                                                             N/A
update                                                                               一个 修改器对象                                                                                     N/A
new                                  若为true,将返回修改后的对象而不是原始对象。在删除操作中,该参数被忽略。                      false
fields                                                           参见Retrieving a Subset of Fields (1.5.0+)                                                            All fields
upsert                                                          创建新对象若查询结果为空。 示例 (1.5.4+)                                                             false

 

语句块操作
1、简单Hello World
print("Hello World!");
这种写法调用了print函数,和直接写入"Hello World!"的效果是一样的;

2、将一个对象转换成json
tojson(new Object());
tojson(new Object('a'));

3、循环添加数据
> for (var i = 0; i < 30; i++) {
    db.users.save({name: "u_" + i, age: 22 + i, sex: i % 2});
  };
这样就循环添加了30条数据,同样也可以省略括号的写法
> for (var i = 0; i < 30; i++) db.users.save({name: "u_" + i, age: 22 + i, sex: i % 2});
也是可以的,当你用db.users.find()查询的时候,显示多条数据而无法一页显示的情况下,可以用it查看下一页的信息;

4、find 游标查询
>var cursor = db.users.find();
> while (cursor.hasNext()) {
    printjson(cursor.next());
}
这样就查询所有的users信息,同样可以这样写
var cursor = db.users.find();
while (cursor.hasNext()) { printjson(cursor.next); }
同样可以省略{}号

5、forEach迭代循环
db.users.find().forEach(printjson);
forEach中必须传递一个函数来处理每条迭代的数据信息

6、将find游标当数组处理
var cursor = db.users.find();
cursor[4];
取得下标索引为4的那条数据
既然可以当做数组处理,那么就可以获得它的长度:cursor.length();或者cursor.count();
那样我们也可以用循环显示数据
for (var i = 0, len = c.length(); i < len; i++) printjson(c[i]);

7、将find游标转换成数组
> var arr = db.users.find().toArray();
> printjson(arr[2]);
用toArray方法将其转换为数组

8、定制我们自己的查询结果
只显示age <= 28的并且只显示age这列数据
db.users.find({age: {$lte: 28}}, {age: 1}).forEach(printjson);
db.users.find({age: {$lte: 28}}, {age: true}).forEach(printjson);
排除age的列
db.users.find({age: {$lte: 28}}, {age: false}).forEach(printjson);

9、forEach传递函数显示信息
db.things.find({x:4}).forEach(function(x) {print(tojson(x));});
上面介绍过forEach需要传递一个函数,函数会接受一个参数,就是当前循环的对象,然后在函数体重处理传入的参数信息。
 

posted @ 2011-06-08 20:13 jadmin 阅读(88) | 评论 (0)编辑 收藏

解决办法:

设置host,在文件 C:\Windows\System32\drivers\etc\hosts 中加入 66.249.89.99  code.google.com

 

posted @ 2011-06-08 15:45 jadmin 阅读(124) | 评论 (0)编辑 收藏

      SD Times高级编辑Alex Handy日前列出了当前使用Hadoop的项目中他认为最成功的五个。

posted @ 2011-06-06 23:10 jadmin 阅读(181) | 评论 (0)编辑 收藏

<script type="text/javascript">
function newGuid()
{
    var guid = "";
    for (var i = 1; i <= 32; i++) {
      var n = Math.floor(Math.random()*16.0).toString(16);
      guid +=   n;
      if((i==8)||(i==12)||(i==16)||(i==20))
        guid += "-";
    }
    return guid;   
}
</script>

 

posted @ 2011-06-01 21:06 jadmin 阅读(102) | 评论 (0)编辑 收藏

这两天在看《编程人生》,这本书确实非常不错。而且看得也特别的轻松。其中有几个人都谈到了如何学习新的语言,但是给我最深刻的是google的首席java架构师joshua bloch。正好最近我也在学习python,所以顺便总结一下如何学习一门新的语言。希望你能补充一些。

心态

这不但是学习一门新的语言最重要的,而是对任何的学习都是最重要的。下面是书中的描述,非常的精彩,特别是那个比喻:

“学习一门新的语言的时候,要利用以前所学的语言的功底,但是也要保持开放的心态。有些人执着于一种理念:“这就是写所有程序必须遵循的方法”。我不是说那种语言,但是某些语言,令人执着于这样的理念。当开始学习新语言的时候,他们会批评这种语言跟真正神的语言的所有的不同之处。当使用新语言时,他们极力使用神的语言的方法去写。这样,你就会错过这个新语言真正的独特之处。
这就像你本来只有一个榔头,有人给了你一个螺丝刀,你说“哎,这不是一把好榔头,但是我应该可以倒着拿螺丝刀,用螺丝刀来砸东西。”你得到了一个很烂的榔头,但事实上它确实一把很不错的螺丝刀。所以你应该对所有的事物保持开放和积极的心态。”

如果你的杯子满了,那他永远再也装不进水了。如果你认为你找到了银弹,那么你可能就要固步自封了。

对新的事物,方法保持一个开发而积极的心态,才能真正了解他,了解他的独特之处。

这一点相对来说比较难,程序员一般对他们的语言有一种近乎固执的偏爱。Paul Graham在《黑客与画家》中好像提到过,开发语言是程序员的宗教信仰,贬低一种语言对使用这种语言的程序员是一种侮辱。

了解他的历史,哲学观

选择一门语言,往往选择了一种思维方式和哲学观。所以,了解一门语言的历史和哲学观非常重要。你要知道这门语言是谁创建的,为什么创建,如何发展起来的,适合那些领域,以及解决问题的哲学是什么。

那python来说,他的设计哲学是“用一种方法,最好是只有一种方法来做一件事”,而perl的设计哲学是“总有多种方法来做同一件事”。所以,我选择的是python。

了解这方面的知识的一个非常好的来源是百科网站。

代码,代码,还是代码

代码是学习一门语言的必经之路,可能也是最快的一种方法。

你不但要找一些优秀的代码来阅读,还要亲自动手来写代码。这个过程对学习语言来说是非常快的。另外,你一定要用语言去解决实际的问题,而不仅仅是写代码来验证语法。在解决问题的过程中,你可以学习它是如何解决问题的,而且会积累语言的经验。

在工作中使用一门新的语言来开发新项目的风险相对较大,所以,如果再工作中尝试使用新的语言,可以选择一些小的项目来积累经验。如果工作中无法使用这个语言,那么就在业余使用这个语言解决问题吧。

社区

多去这个语言的社区逛逛吧,这里有很多人在讨论这种语言,和他们一起讨论你能够学到更多。


本文转自CSDN博客

posted @ 2011-06-01 12:48 jadmin 阅读(74) | 评论 (0)编辑 收藏

/**
* Java + MongoDB in Secure Mode
*
* @author <a href="mailto:gerald.chen@qq.com">Gerald Chen</a>
* @version $Id: AuthTest.java,v 1.1 2011/05/27 07:24:04 gerald.chen Exp $
*/

public class AuthTest {
 
/** 数据库连接IP */
public static final String DB_HOST ="192.168.35.101";
 
/** 数据库连接端口 */
public static final int DB_PORT =27017;
 
public static void main(String[] args) throws Exception, MongoException {
      Mongo mongo =new Mongo(DB_HOST, DB_PORT);
      DB db = mongo.getDB("test_db");
 
      boolean auth = db.authenticate("gerald", "123456".toCharArray());
      System.out.println(auth);
 
      DBCollection collection = db.getCollection("test_collection");
      System.out.println(collection.getFullName());
 
}
 
}

posted @ 2011-05-27 15:42 jadmin 阅读(96) | 评论 (0)编辑 收藏

1.进入mongodb命令行管理
C:\Documents and Settings\Administrator>mongo
MongoDB shell version: 1.8.1
connecting to: test

 

2.显示数据库
> show dbs
admin   (empty)
local   (empty)
test_db 0.03125GB

 

3.使用数据库
> use test_db
switched to db test_db

 

4.添加数据库用户
> db.users.save({username:"gerald"})

 

5.查找数据库用户
> db.users.find()
{ "_id" : ObjectId("4ddf396e641b4986d346fe89"), "username" : "gerald" }

 

6.添加隶属于某个数据库的用户
> use test_db
switched to db test_db
> db.addUser("gerald","123456")
{
        "user" : "gerald",
        "readOnly" : false,
        "pwd" : "f528f606b8635241c7f060408973b5b9"
}

 

7.以用户验证的身份登录数据库
> use test_db
switched to db test_db
> db.auth("gerald","123456")
1

PS: 1代表验证成功, 0代表验证失败

 

关键词:数据库  NoSQL  MongoDB  Database

 

posted @ 2011-05-27 15:38 jadmin 阅读(105) | 评论 (0)编辑 收藏