-
Notifications
You must be signed in to change notification settings - Fork 56
DasClient 使用手册
DasClient是用户操作数据库的统一接口。通过DasClient可以方便的对数据库进行增删改查。DasClient覆盖的功能范围和场景非常全面,既可以通过实体,也可以通过SQL进行ORM操作,同时还支持存储过程和事务
DasClient接口主要和Code Gen生成的实体,SqlBuilder配合使用。为在保持API简洁易用的情况下覆盖尽可能多的场景,每个接口可以使用Hints来支持同一类操作不同的变种。
DasClient支持透明的分库分表。绝大多数场景下用户体验和未分库时保持一致。极少数情况下当上下文无法判断如何分库分表的时候,可以通过Hints人工指定。
我们将给出常用的一些示例帮助你更方便使用DAS Client。
DasClient的创建非常简单,只需提供逻辑数据库名即可。每个DasClient实例对应所有可以在该逻辑数据库上面进行的操作。实例是线程安全的对象,可以跨线程使用。
DasClient dao = DasClientFactory.getClient("logicDbName");你也可以参考Sample spring boot工程详解中的代码,将DasClient配置成Spring bean。
获得指定逻辑数据库的dao后,即可对数据库进行操作。操作按照参数可以分三种类型:
-
基于表实体的CRUD操作。包括单个实体的CRUD和多个实体的批量CRUD操作
-
基于SQL builder的操作,具体包括:
-
SqlBuilder:构建任意的一条SQL语句 -
BatchUpdateBuilder:构建批量操作,分两类,一类是同一条语句,多组参数;一类是多不同条语句,无参数 -
CallBuilder:构建存储过程调用 -
BatchCallBuilder:构建对存储过程的批量调用
-
-
事务操作。分为带返回值的事务和无返回值的事务操作 注意,
Hints作为可选参数,可以不提供,但提供时,只能提供一个。由于Hints会存储操作的额外指令或操作的审计信息,因此Hints不推荐反复使用,请在需要使用的时候创建新的实例。
示例:
Person pk = new Person();
pk.setPeopleID(1);
pk = dao.queryByPk(pk); //返回主键为1的数据示例:
Person sample = new Person();
sample .setName("test");
List<Person> plist = dao.queryBySample(sample );//返回name是"test"的数据示例:
Person sample = new Person();
sample.setName("test");
List<Person> plist = dao.queryBySample(sample);//返回name是"test"的数据示例:
Person sample = new Person();
sample.setName("test");
Person.PersonDefinition p = Person.PERSON;
//分页:每页10条,返回第1页数据(第1页是头一页)
List<Person> plist = dao.queryBySample(sample, PageRange.atPage(1, 10, p.PeopleID));
//分页:每页10条,返回第2页数据,按照CityID和CountryID升序
plist = dao.queryBySample(sample, PageRange.atPage(2, 10, p.CityID, p.CountryID), hints);
//分页:每页10条,返回第1页数据,按照PeopleID升序和CityID降序
plist = dao.queryBySample(sample, PageRange.atPage(1, 10, p.PeopleID.asc(), p.CityID.desc()), hints);示例:
Person sample = new Person();
sample.setName("test");
long count = dao.countBySample(sample);//返回name是"test"的数据的条数示例:
Person.PersonDefinition p = Person.PERSON;
SqlBuilder builder = SqlBuilder.selectAllFrom(p)
.where().allOf(p.PeopleID.eq(peopleId), p.CountryID.eq(countryID))
.into(Person.class);
Person person = dao.queryObject(builder);示例:
Person.PersonDefinition p = Person.PERSON;
SqlBuilder builder = SqlBuilder.selectAllFrom(p)
.where()
.allOf(p.CountryID.eq(countryID).nullable(), p.CityID.eq(cityID))
.orderBy(p.PeopleID.asc())
.into(Person.class);
List<Person> plist = dao.query(builder);//支持原生SQL
SqlBuilder builder = new SqlBuilder()
.appendTemplate("select * from person where PeopleID = ? AND CountryID = ?", Parameter.integerOf("", 3), Parameter.integerOf("", 4))
.into(Person.class);
List<Person> plist = dao.query(builder);示例:
BatchQueryBuilder batchBuilder = new BatchQueryBuilder();
Person.PersonDefinition p = Person.PERSON;
for (int j = 0; j < TABLE_MODE; j++) {
List<Integer> pks = new ArrayList<>();
for (int k = 0; k < TABLE_MODE; k++)
pks.add(k + 1);
SqlBuilder builder = SqlBuilder.selectAllFrom(p)
.where()
.allOf(p.PeopleID.in(pks), p.CountryID.eq(i), p.CityID.eq(j))
.orderBy(p.PeopleID.asc())
.into(Person.class);
batchBuilder.addBatch(builder);
}
List<List<Person>> plist = (List<List<Person>>)dao.batchQuery(batchBuilder);示例:
Person.PersonDefinition p = Person.PERSON;
SqlBuilder builder = SqlBuilder.selectCount().from(p).intoObject();
Number count = dao.queryObject(builder);利用limit的MySQL示例:
Person.PersonDefinition p = Person.PERSON;
SqlBuilder builder = SqlBuilder.selectAllFrom(p)
.orderBy(p.PeopleID.asc())
.into(Person.class)
.limit(2, 10);
List<Person> plist = dao.query(builder);利用top和offset的SQLServer示例:
//use OFFSET
Person.PersonDefinition p = Person.PERSON;
SqlBuilder builder = SqlBuilder.selectAllFrom(p)
.orderBy(p.PeopleID.asc())
.into(Person.class)
.offset(2, 10);
List<Person> plist = dao.query(builder);
//use TOP
SqlBuilder builder2 = SqlBuilder.selectAllFrom(p)
.orderBy(p.PeopleID.asc())
.into(Person.class)
.top(10);
List<Person> plist2 = dao.query(builder2);示例:
Person person = new Person();
person.setName("jerry");
person.setCountryID(1);
person.setCityID(2);
dao.insert(person);
//设置主键后插入
person.setPeopleID(1);
dao.insert(person, Hints.hints().insertWithId());
//person对象插入后id会被填充
dao.insert(person, Hints.hints().setIdBack());示例:
List<Person> pl = new ArrayList<>();
for(int k = 0; k < 4; k++) {
Person p = new Person();
p.setName("jerry");
p.setCountryID(k);
p.setCityID(k);
pl.add(p);
}
assertEquals(4, dao.insert(pl));示例:
List<Person> pl = new ArrayList<>();
for(int k = 0; k < 4; k++) {
Person p = new Person();
p.setName("jerry");
p.setCountryID(k);
p.setCityID(k);
pl.add(p);
}
int[] ret = dao.batchInsert(pl);示例:
Person pk = new Person();
pk.setPeopleID(1);
pk.setName("Tom");
pk.setCountryID(1);
pk.setCityID(2);
assertEquals(1, dao.update(pk));示例:
List<Person> pl = new ArrayList<>();
for (int k = 0; k < 4; k++) {
Person pk = new Person();
pk.setPeopleID(peopleId);
pk.setName("Tom");
pk.setCountryID(1);
pk.setCityID(2);
pl.add(pk);
}
int[] ret = dao.batchUpdate(pl);示例:
Person.PersonDefinition p = Person.PERSON;
SqlBuilder builder = SqlBuilder.update(p)
.set(p.Name.eq("Tom"), p.CountryID.eq(100), p.CityID.eq(200))
.where(p.PeopleID.eq(1));
assertEquals(1, dao.update(builder));
SqlBuilder builder = SqlBuilder.deleteFrom(p)
.where(p.PeopleID.eq(1));
SqlBuilder builder = SqlBuilder.update(p)
.set(p.Name.eq("Tom"), p.CountryID.eq(100), p.CityID.eq(200))
.where(p.PeopleID.eq(1));
SqlBuilder builder = SqlBuilder.insertInto(p, p.Name, p.CountryID)
.values(p.Name.of("Jerry"), p.CountryID.of(dbShard));示例:
String[] statements = new String[]{
"INSERT INTO " + TABLE_NAME + "( Name, CityID, ProvinceID, CountryID)"
+ " VALUES( 'test', 10, 1, 1)",
"INSERT INTO " + TABLE_NAME + "( Name, CityID, ProvinceID, CountryID)"
+ " VALUES( 'test', 10, 1, 1)",
"INSERT INTO " + TABLE_NAME + "( Name, CityID, ProvinceID, CountryID)"
+ " VALUES( 'test', 10, 1, 1)",};
BatchUpdateBuilder builder = new BatchUpdateBuilder(statements);
int[] ret = dao.batchUpdate(builder);单条语句,多组值更新:
Person.PersonDefinition p = Person.PERSON;
BatchUpdateBuilder builder = new BatchUpdateBuilder(
"INSERT INTO " + TABLE_NAME + "( Name, CityID, ProvinceID, CountryID) VALUES( ?, ?, ?, ?)",
varcharVar("Name"), integerVar("CityID"), integerVar("ProvinceID"), integerVar("CountryID"));
builder.addBatch("test", 10, 1, 1);
...
int[] ret = dao.batchUpdate(builder);
//另外一种方式,直接用列定义参数
BatchUpdateBuilder builder = new BatchUpdateBuilder(
"INSERT INTO " + TABLE_NAME + "( Name, CityID, ProvinceID, CountryID) VALUES( ?, ?, ?, ?)",
p.Name, p.CityID, p.ProvinceID, p.CountryID);
builder.addBatch("test", 10, 1, 1);使用SqlBuilder:
BatchUpdateBuilder builder = new BatchUpdateBuilder(
SqlBuilder.insertInto(p, p.Name, p.CityID, p.ProvinceID, p.CountryID).values(
varcharVar("Name"), integerVar("CityID"), integerVar("ProvinceID"), integerVar("CountryID")));
builder.addBatch("test", 10, 1, 1);
。。。
//另外一种定义参数的方式
BatchUpdateBuilder builder = new BatchUpdateBuilder(
SqlBuilder.insertInto(p, p.Name, p.CityID, p.ProvinceID, p.CountryID).values(
p.Name.var(), p.CityID.var(), p.ProvinceID.var(), p.CountryID.var()));
builder.addBatch("test", 10, 1, 1);
//Update的例子:
BatchUpdateBuilder builder = new BatchUpdateBuilder(
SqlBuilder.update(p).set(
p.Name.eq(varcharVar("Name")),
p.CityID.eq(integerVar("CityID")),
p.ProvinceID.eq(integerVar("ProvinceID")),
p.CountryID.eq(integerVar("CountryID")))
.where(p.DataChange_LastTime.eq(timestampVar("DataChange_LastTime"))));
builder.addBatch("test", 10, 1, 1, new java.sql.Timestamp(new Date().getTime()));
builder.addBatch("test", 10, 1, 1, new java.sql.Timestamp(new Date().getTime()));
builder.addBatch("test", 10, 1, 1, new java.sql.Timestamp(new Date().getTime()));
dao.batchUpdate(builder);示例:
Person pk = new Person();
pk.setPeopleID(peopleId);
assertEquals(1, dao.deleteByPk(pk));示例:
Person sample = new Person();
sample.setName("test");
dao.deleteBySample(sample);示例:
List<Person> pl = new ArrayList<>();
for (int k = 0; k < 4; k++) {
Person pk = new Person();
pk.setPeopleID(peopleId);
pk.setCountryID(k);
pk.setCityID(k);
pl.add(pk);
}
int[] ret = dao.batchDelete(pl);示例: 包含input参数:
CallBuilder cb = new CallBuilder(SP_WITHOUT_OUT_PARAM);
cb.registerInput("v_id", JDBCType.INTEGER, 7);
cb.registerInput("v_cityID", JDBCType.INTEGER, 7);
cb.registerInput("v_countryID", JDBCType.INTEGER, 7);
cb.registerInput("v_name", JDBCType.VARCHAR, "666");
dao.call(cb);包含output参数:
CallBuilder cb = new CallBuilder(SP_WITH_OUT_PARAM);
cb.registerInput("v_id", JDBCType.INTEGER, 4);
cb.registerOutput("count", JDBCType.INTEGER);
dao.call(cb);包含inout参数:
CallBuilder cb = new CallBuilder(SP_WITH_IN_OUT_PARAM);
cb.registerInput("v_id", JDBCType.INTEGER, 3);
cb.registerInput("v_cityID", JDBCType.INTEGER, 7);
cb.registerInput("v_countryID", JDBCType.INTEGER, 7);
cb.registerInputOutput("v_name", JDBCType.VARCHAR, "666");
cb.hints().inShard(i);
dao.call(cb);示例: 包含input参数:
BatchCallBuilder cb = new BatchCallBuilder(SP_WITHOUT_OUT_PARAM);
cb.registerInput("v_id", JDBCType.INTEGER);
cb.registerInput("v_cityID", JDBCType.INTEGER);
cb.registerInput("v_countryID", JDBCType.INTEGER);
cb.registerInput("v_name", JDBCType.VARCHAR);
cb.addBatch(7, 7, 7, "777");
cb.addBatch(17, 17, 17, "1777");
cb.addBatch(27, 27, 27, "2777");
int[] ret = dao.batchCall(cb);示例: 包含input参数:
PersonDefinition p = Person.PERSON;
dao.execute(() -> {
SqlBuilder builder = SqlBuilder.selectAllFrom(p)
.where(p.PeopleID.gt(0))
.orderBy(p.PeopleID.asc())
.into(Person.class);
List<Person> plist = dao.query(builder);
assertEquals(4, plist.size());
assertArrayEquals(new int[] {1, 1, 1, 1}, dao.batchDelete(plist));
builder = SqlBuilder.selectAllFrom(p)
.where(p.PeopleID.gt(0))
.orderBy(p.PeopleID.asc())
.into(Person.class);
assertEquals(0, dao.query(builder).size());
assertEquals(4, dao.insert(plist));
builder = SqlBuilder.selectAllFrom(p)
.where(p.PeopleID.gt(0))
.orderBy(p.PeopleID.asc())
.into(Person.class);
assertEquals(4, dao.query(builder).size());
});示例: 包含input参数:
PersonDefinition p = Person.PERSON;
List<Person> plistx = dao.execute(() -> {
SqlBuilder builder = SqlBuilder.selectAllFrom(p)
.where(p.PeopleID.gt(0))
.orderBy(p.PeopleID.asc())
.into(Person.class);
List<Person> plist = dao.query(builder);
assertEquals(4, plist.size());
assertArrayEquals(new int[] {1, 1, 1, 1}, dao.batchDelete(plist));
builder = SqlBuilder.selectAllFrom(p)
.where(p.PeopleID.gt(0))
.orderBy(p.PeopleID.asc())
.into(Person.class);
assertEquals(0, dao.query(builder).size());
assertEquals(4, dao.insert(plist));
builder = SqlBuilder.selectAllFrom(p)
.where(p.PeopleID.gt(0))
.orderBy(p.PeopleID.asc())
.into(Person.class);
assertEquals(4, dao.query(builder).size());
return plist;
});@DasTransactional需要在Spring容器环境下才能工作,此注解需修饰Spring bean内定义的方法。
示例:
@Service
public class MyService {
@DasTransactional(logicDbName = "logicDBName")
public void execute() {
//DAS的操作
}
...
}同时支持单元测试情景下的自动回滚,例如:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
DasTransactionalEnabler.class, //需要注入此bean
AnnotationAwareAspectJAutoProxyCreator.class, //需要注入此bean,等价于XML中声明<aop:aspectj-autoproxy/>
DasTest.class,
DaoBean.class})
@SpringBootTest
public class DasTest {
@Autowired
DaoBean daoBean;
@Test
public void test() throws SQLException {
daoBean.foo();
}
}
@Component
public class DaoBean {
@DasTransactional(logicDbName = DB_NAME, rollback = true) //foo方法中的数据操作都会被自动rollback
public void foo() throws SQLException {
//DAS的操作
}
}