Skip to content

Java客户端 功能简介

He, Jiehui edited this page Aug 5, 2016 · 8 revisions

简介

dal客户端也称dal client或client。是实现数据库访问的api层。主要是配合code gen生成的代码,提供生成代码使用的底层api。请直接使用code gen产生的代码,不要自己修改或试图手工调用api。

本文主要介绍一些常用的功能如何通过dal client完成

获得自增主键

Keyholder usage

如果数据库支持自增长id,那么在插入包含自增长id的表的时候,DAL会过滤掉原有的id,并在KeyHolder里面返回生产的id。

支持的DalTableDao API,参数里面包含KeyHolder的插入操作,都支持

public int combinedInsert(DalHints hints, KeyHolder keyHolder, List<T> daoPojos)

public int[] insert(DalHints hints, KeyHolder keyHolder, List<T> daoPojos)

通过code gen生成的DAO里面的insert方法如果包含KeyHolder参数,说明该方法支持自增长id,并且用法一样。

注意

不是所有的插入操作都会返回自增长id。批处理的插入就无法返回。

public int[] batchInsert(DalHints hints, List<T> daoPojos)

Keyholder常用API

如果只插入一条数据,可以通过getKey来得到返回的自增长id public Number getKey()

如果是一系列数据库,可以通过getIdList()得到 public List getIdList()

其他API

得到第n个pojo对应的id

public Number getKey(int index)

得到数据库返回的原始格式的key,仅限于插入一条的情况

public Map<String, Object> getKeys()

得到数据库返回的原始格式的key,适用于插入多条的情况

public List<Map<String, Object>> getKeyList()

其他问题

顺序和shard

KeyHolder里面放的返回的自增长id的的顺序是传入到insert或combinedInsert里面的pojo的顺序。即使在逻辑数据库支持分片的情况下,DAL也会按照pojo的顺序汇总各个shard生成id的结果

异步支持

KeyHolder支持DAO层面的异步操作,如果异步调用DAO,对KeyHolder的访问不受影响,用法和同步一致

代码示例

调用生成的DAO,插入一条

    private void insert(HttpServletRequest request, HttpServletResponse response) throws Exception {
        KeyHolder keyHolder = new KeyHolder();
        dao.insert(readHints(request).setKeyHolder(keyHolder), readPeople(request));
        response.getWriter().write("Insert success. Id : " + keyHolder.getKey());
    }

代码示例2,插入多条

holder = createKeyHolder();
res = dao.combinedInsert(new DalHints().inShard(i), holder, entities);
assertResEquals(3, res);
assertEquals(3 + j++ * 3, getCountByDb(dao, i));
assertKeyHolder(holder);

插入自定义主键

如果表的主键是自增长的字段,缺省的插入操作会把传入的主键去掉。可以通过设置hint来允许使用传入的主键

dao.insert(new DalHints().enableIdentityInsert(), daoPojo);

例子

for(int i = 1; i < 11; i++) {
    PersonGen daoPojo = createPojo(i);
    try {
        dao.insert(new DalHints().enableIdentityInsert(), daoPojo);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

敏感参数与字段处理

敏感参数处理

在code gen里面创建构建和自定义DAO的时候,可以指定参数是否为敏感。

如果参数是敏感的,则用特殊的setSenstive方法来设置参数。否则用正常的set。

public int test_build_insert (String Name, Integer Age, DalHints hints) throws SQLException {
    String sql = SQLParser.parse("INSERT INTO person (`Name`,`Age`) VALUES ( ? , ? )");
    StatementParameters parameters = new StatementParameters();
    hints = DalHints.createIfAbsent(hints);
    int i = 1;
    parameters.setSensitive(i++, "Name", Types.VARCHAR, Name);
    parameters.setSensitive(i++, "Age", Types.INTEGER, Age);
    return client.update(sql, parameters, hints);
}

敏感字段处理

在entity里面可以通过@Sensitive来指定字段是否为敏感。

@Id
@Column(name="ID")
@GeneratedValue(strategy = GenerationType.AUTO)
@Type(value=Types.INTEGER)
@Sensitive(value=true)
private Integer iD;
 
@Column(name="Name")
@Type(value=Types.VARCHAR)
@Sensitive(value=true)
private String name;
 
@Column(name="Age")
@Type(value=Types.INTEGER)
@Sensitive(value=true)
private Integer age;

敏感标记处理

Senstive会影响log记录的信息。如果参数或field被标记为senstive,则log的时候会把对应的值替换为*

Multiple Query Request

允许用户通过一个DB请求执行多条sql。相关API位于DalQueryDao public List<?> query(MultipleSqlBuilder mqr, StatementParameters parameters, DalHints hints) throws SQLException;

MultipleSqlBuilder API

MultipleSqlBuilder提供多个重载方法方便构建MultipleSqlBuilder

public <T> MultipleSqlBuilder add(String sql, DalResultSetExtractor<T> extractor, ResultMerger<T> merger);
public <T> MultipleSqlBuilder addQuery(String sql, DalRowMapper<T> mapper);
public <T> MultipleSqlBuilder addQuery(String sql, DalRowMapper<T> mapper, ResultMerger<List<T>> merger);
public <T> MultipleSqlBuilder addQuery(String sql, DalRowMapper<T> mapper, Comparator<T> sorter);
public <T> MultipleSqlBuilder addQuery(String sql, Class<T> clazz) throws SQLException;
public <T> MultipleSqlBuilder addQuery(String sql, Class<T> clazz, ResultMerger<List<T>> merger) throws SQLException;
public <T> MultipleSqlBuilder addQuery(String sql, Class<T> clazz, Comparator<T> sorter) throws SQLException;
public MultipleSqlBuilder addQuery(String sql, DalRowCallback callback);

代码示例

      private String sqlList = "select * from " + TABLE_NAME;
      private String sqlListQuantity = "select quantity from " + TABLE_NAME;
      private String sqlObject = "select * from " + TABLE_NAME + " where id = ? and type=0";
      private String sqlFirst = "select * from " + TABLE_NAME + " where id = ?";
      private String sqlNoResult = "select * from " + TABLE_NAME + " where id = -1";
      private String sqlIdInParam = "select * from " + TABLE_NAME + " where id in (?)";
    
      private List queryMultipleAllShards(DalHints hints) throws SQLException {
          DalQueryDao dao = new DalQueryDao(DATABASE_NAME);
           
          StatementParameters parameters = new StatementParameters();
          parameters.set(1, Types.INTEGER, 1);
           
          MultipleSqlBuilder builder = new MultipleSqlBuilder();
          // TODO add all add method
          builder.addQuery(sqlList, new StatementParameters(), new ClientTestDalRowMapper());//mapper
          builder.addQuery(sqlList, new StatementParameters(), new ClientTestDalRowMapper(), new        DalListMerger<ClientTestModel>());//merger
          builder.addQuery(sqlList, new StatementParameters(), ClientTestModel.class, new ClientTestModelComparator());//sorter
          builder.addQuery(sqlListQuantity, new StatementParameters(), Integer.class, new DalListMerger<Integer>());//merger
          builder.addQuery(sqlObject, parameters, Integer.class, new InteregrComparator());//soter
          builder.addQuery(sqlNoResult, new StatementParameters(), new TestDalRowCallback3());//callback
          List<Integer> inParam = new ArrayList<>();
          inParam.add(0);
          inParam.add(1);
          inParam.add(2);
          inParam.add(3);
          inParam.add(4);
          parameters.setInParameter(1, "type", Types.INTEGER, inParam);
          builder.addQuery(sqlIdInParam, new StatementParameters(), ClientTestModel.class);
          return dao.query(builder, hints.inAllShards());
   }

异步操作

目前DalTableDao和DalQueryDao里面的所有API都已支持异步操作。对异步的支持是通过DalHints来实现的,没有新添加API。对异步的支持是由内部的DalRequestExecutor来实现,在DAO这层发生,不涉及到DalClient的改动。

目前对异步的支持有两种形式:异步返回执行结果和异步调用回调接口。无论是那种形式都判定为异步操作。

异步返回结果

在调用任何DAO的API之前设置DalHints为异步执行模式,则执行的结果会放到hints里面,原方法返回null或0。应用在调用结束后取得Future即可。

DalHints().asyncExecution()

代码示例如下

@Test
public void testQueryByPkAsync() throws SQLException {
    ClientTestModel model = null;
    DalHints hints;
    for(int i = 0; i < mod; i++) {
        // By shard
        hints = new DalHints().asyncExecution();
        if(i%2 == 0)
            model = dao.queryByPk(1, hints.inShard(String.valueOf(i)));
        else
            model = dao.queryByPk(1, hints.inShard(i));
         
        assertNull(model);
        model = getModel(hints);
        assertEquals(1, model.getId().intValue());
        assertEquals(i, model.getTableIndex().intValue());
===
private ClientTestModel getModel(DalHints hints) throws SQLException {
    try {
        return (ClientTestModel)hints.getAsyncResult().get();
    } catch (Exception e) {
        throw new SQLException(e);
    }
}

异步回调

在调用任何DAO的API之前设置DalHints为异步回调模式, 传入回调接口,系统会根据执行情况的正常与否,调用不同的API。 注意

就算是使用回调形式,Dal还是会把异步执行的结果放到hints里面。以备查询的方便。应用如果用不到,可以简单忽略,无需处理。

代码示例如下

public interface DalResultCallback {
    <T> void onResult(T result);
    void onError(Throwable e);
}

@Test
public void testQueryByPkCallback() throws SQLException {
    ClientTestModel model = null;
    DalHints hints;
    TestQueryResultCallback callback;
    for(int i = 0; i < mod; i++) {
        // By shard
        callback = new TestQueryResultCallback();
        hints = new DalHints().callbackWith(callback);
        if(i%2 == 0)
            model = dao.queryByPk(1, hints.inShard(String.valueOf(i)));
        else
            model = dao.queryByPk(1, hints.inShard(i));
         
        assertNull(model);
        model = callback.get();
        assertEquals(1, model.getId().intValue());
        assertEquals(i, model.getTableIndex().intValue());
====
private class TestQueryResultCallback implements DalResultCallback {
    private AtomicReference<ClientTestModel> model = new AtomicReference<>();
     
    @Override
    public <T> void onResult(T result) {
        model.set((ClientTestModel)result);
    }
     
    public ClientTestModel get() {
        while(model.get() == null)
            try {
                Thread.sleep(1);
            } catch (Exception e) {
                return null;
            }
        return model.get();
    }
    @Override
    public void onError(Throwable e) {
        // TODO Auto-generated method stub
         
    }
}

帮助类

为方便测试,Dal提供了回调接口的缺省实现DefaultResultCallback,可在com.ctrip.platform.dal.dao.helper找到。API如下

com.ctrip.platform.dal.dao.helper.DefaultResultCallback

onResult(T)
onError(Throwable)
waitForDone()//等待调用结束
waitForDone(int)//等待调用结束,可以设置timeout,单位为毫秒
isDone()//是否结束
isSuccess()//是否成功
getResult()//得到成功的结果
getError()//得到出错的异常
reset()//重置,可以再次利用
Clone this wiki locally