十.annotations注解包
Mybatis使用注解的方式可以減少使用xml配置sql,方便用斷點的形式檢測生成的sql,代碼的可讀性更強,更利于維護。
10.1Param注解
用于定義接口入?yún)⒌膭e名,方便代碼運行時獲取接口入?yún)?,而不至于讀取參數(shù)表中的參數(shù)時因為參數(shù)類型相同而導致參數(shù)獲取紊亂。
用法:
List<T> selectByIdAndName (@Param("id") Integer id, @Param("name") String name);
10.2Select注解
給指定的mapper接口增加sql語句實現(xiàn)查詢功能,使用方法為:
@Select("select * from users")
List<User> getAllUsers();
10.3SelectProvider注解
方便動態(tài)生成sql語句,可以在注解中聲明自定義生成sql語句的方法和類的type:
//聲明自定義的Provider的type,以及自定義Provider中的方法名
@SelectProvider(type = StatementProvider.class, method = "provideSelect")
S select(S param);
//自定義的sql生成方法
public String provideSelect(Object param) {
StringBuilder sql = new StringBuilder("select * from ");
if (param == null || param instanceof Person) {
sql.append(" person ");
if (param != null && ((Person) param).getId() != null) {
sql.append(" where id = #{id}");
}
} else if (param instanceof Country) {
sql.append(" country ");
if (((Country) param).getId() != null) {
sql.append(" where id = #{id}");
}
}
sql.append(" order by id");
return sql.toString();
}
10.4SelectKey注解
用于在sql語句執(zhí)行前(后)插入執(zhí)行,如在執(zhí)行前(后)查詢當前自增張id的值,注解中聲明的屬性為:
//sql子句
String[] statement();
//屬性名,將查詢得到列中的數(shù)據(jù)賦值屬性名對應的屬性
String keyProperty();
//查詢返回的列名
String keyColumn() default "";
//表示在是否在主sql執(zhí)行前執(zhí)行
boolean before();
//返回的值的類型
Class<?> resultType();
//狀態(tài)
StatementType statementType() default StatementType.PREPARED;
具體使用方式為:
(1)sql語句執(zhí)行后
@Update("update table2 set name = #{name} where id = #{nameId}")
//在更新語句后執(zhí)行,查詢nameId對應的name_fred,并賦值給Name類的generatedName屬性(入?yún)ame的generatedName屬性)
@SelectKey(statement="select name_fred from table2 where id = #{nameId}",
keyProperty="generatedName", keyColumn="NAME_FRED", before=false, resultType=String.class)
int updateTable2WithSelectKeyWithKeyMap(Name name);
(2)sql語句執(zhí)行前
@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
//在插入語句執(zhí)行之前,查詢數(shù)據(jù)庫表中下一個id的值,并賦值給Name對象name的nameId屬性
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
int insertTable3(Name name);
10.5 Insert、InsertProvider注解
使用方法與Select相似。
10.6 Update、UpdateProvider注解
使用方法和Select相似。
10.7 Delete、DeleteProvider注解
使用方法和Select相似。
10.8 Mapper注解
使用該注解時只需要在對應的mapper的接口上添加注解@Mapper即可讓spring加載這個Bean,且根據(jù)注解定義的sql語句實現(xiàn)功能。不過這個注解的加載不是在mybatis的主jar包中,而是在這個jar中找到了這個方法:
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
logger.debug("Searching for mappers annotated with @Mapper");
//mapper類路徑掃描器,這個類在mybatis-spring中,繼承自spring框架下的ClassPathBeanDefinitionScanner類。
//說明如果不引入mybatis-spring-boot-autoconfigure這個jar也可以用這個類加載mapper
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
try {
if (this.resourceLoader != null) {
//設置資源加載器
scanner.setResourceLoader(this.resourceLoader);
}
//從工廠中知道哪些包路徑是需要自動掃描的
List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
if (logger.isDebugEnabled()) {
for (String pkg : packages) {
logger.debug("Using auto-configuration base package '{}'", pkg);
}
}
//設置需要掃描的注解類型
scanner.setAnnotationClass(Mapper.class);
//注冊過濾器
scanner.registerFilters();
//開始掃描
scanner.doScan(StringUtils.toStringArray(packages));
} catch (IllegalStateException ex) {
logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
}
}
10.9 AutomapConstructor注解
在與數(shù)據(jù)庫查詢結果對應的model類的構造器上增加這個注釋,可以讓框架自動使用這個構造器。
10.11 ResultType注解
用于注明結果類型,使用方式為:
@Select("select * from users")
@ResultType(User.class)
//雖然方法的返回結果為void,但是入?yún)esultHandler可以接受返回結果
void getAllUsers(UserResultHandler resultHandler);
其中UserResultHandler為:
public class UserResultHandler implements ResultHandler {
//返回結果
private List<User> users;
public UserResultHandler() {
super();
users = new ArrayList<User>();
}
@Override
public void handleResult(ResultContext context) {
User user = (User) context.getResultObject();
users.add(user);
}
public List<User> getUsers() {
return users;
}
}
10.12One、Many注解
用于注明查詢結果是1對1(1對多)的關系,fetchType屬性可以配置為懶加載或者立即加載:
@Results({
@Result(property = "author", column = "author_id", one = @One(select = "org.apache.ibatis.binding.BoundAuthorMapper.selectAuthor", fetchType=FetchType.EAGER)),
@Result(property = "posts", column = "id", many = @Many(select = "selectPostsById", fetchType=FetchType.EAGER))
})
List<Blog> selectBlogsWithAutorAndPostsEagerly();
10.13Lang注解
該注解用于標注使用的自定義語言腳本驅動(自定義實現(xiàn)自LanguageDriver接口的類),方便于解析sql語言,使用時只需要在對應方法上增加注解,如:
@Lang(XMLLanguageDriver.class)
10.14Flush注解
使用這個注解的方式應該是在對應的方法上增加注解@Flush,然后調用方法時會將緩存中的操作批量刷新到數(shù)據(jù)庫中,因為官方給的文檔不夠詳細,本人也沒有實踐過,如果存在理解錯誤,請諒解。
10.13Results、ResultMap、Result注解
這幾個注解用于查詢結果的映射,用于將數(shù)據(jù)庫中的字段名和java對象中的字段名對應上,不過目前也可以使用數(shù)據(jù)庫提供的別名定義的方式實現(xiàn)名稱映射,同時也可以使用自定義typeHandle處理
10.13.1 ResultMap應用
//在這個結果集中定義映射名叫userResult,方便別的地方去使用
@Results(id = "userResult", value = {
//定義uid到id的映射
@Result(id = true, column = "uid", property = "id"),
@Result(column = "name", property = "name")
})
@Select("select * from users where uid = #{id}")
User getUserById(Integer id);
//在這里通過復用之前定義好的id=userResult的映射完成結果集映射
@ResultMap("userResult")
@Select("select * from users where name = #{name}")
User getUserByName(String name);
10.13.2Result說明
//標注是不是id,一般id會被定義成數(shù)據(jù)庫中的序列化主鍵
boolean id() default false;
//數(shù)據(jù)庫查詢結果中的列名
String column() default "";
//需要映射的對象中的屬性名
String property() default "";
//java的類型
Class<?> javaType() default void.class;
//數(shù)據(jù)庫中的類型
JdbcType jdbcType() default JdbcType.UNDEFINED;
//自定義類型處理器
Class<? extends TypeHandler<?>> typeHandler() default UnknownTypeHandler.class;
//標注為單條結果映射
One one() default @One;
//表示為多條結果映射
Many many() default @Many;
10.13.3Results應用
具體使用時,在需要定義結果映射的方法前增加注釋,就可以將查詢到的結果按照定義好的結果映射樣式完成映射。
//這里的注解中的參數(shù)只是為了展示方便定義的,目的是為了展示注解的使用方法,可能存在錯誤
@Select("select * from post where author_id = #{id} order by id")
@Results(id = "test",
value = {@Result(property = "id", column = "id",javaType = int.class,jdbcType = JdbcType.INTEGER),
@Result(property = "subject", column = "subject"),
@Result(property = "body", column = "body"),
@Result(property = "tags", javaType = List.class, column = "id", typeHandler = ArrayTypeHandler.class,
many = @Many(select = "getTagsForPost"))
})
List<AnnoPost> getPosts(int authorId);
10.14Options
這個注解用于配置查詢結果配置,內(nèi)部具有如下屬性:
//是否使用緩存
boolean useCache() default true;
//是否清除緩存
FlushCachePolicy flushCache() default FlushCachePolicy.DEFAULT;
//結果集的類型
ResultSetType resultSetType() default ResultSetType.FORWARD_ONLY;
//執(zhí)行語句生成方式類型
StatementType statementType() default StatementType.PREPARED;
//返回結果條目數(shù)
int fetchSize() default -1;
//查詢超時時間
int timeout() default -1;
//是否使用自增長key
boolean useGeneratedKeys() default false;
//key在結果對象中的屬性名
String keyProperty() default "";
//key在數(shù)據(jù)庫中的列名
String keyColumn() default "";
//不清楚怎么用
String resultSets() default "";
常見的使用方式為返回插入數(shù)據(jù)對應的自增長序列id:
@Options(useGeneratedKeys = true, keyProperty = "id ")
@Insert({ "insert into planet (name) values (#{name})" })
//注意,不是把id作為方法的返回值,而是將id賦值給plate對象的id屬性。
int insertPlanet(Planet planet);
10.15MapKey
標注返回結果的map的鍵值為對象中的哪個字段,如Person中存在一個字段名為id的屬性,MapKey的value設置為id,那么返回的map中key的值就是id的值,如:
@Select("select * from person")
@MapKey("id")
Map<Integer, Person> selectAsMap();
10.16 CacheNamespace、Property、CacheNamespaceRef注解
這個應該是用于命名空間中的緩存讀取,具體使用方法為在類名上加CacheNamespace注解,然后通過Property設置值:
@CacheNamespace(implementation = CustomCache.class, properties = {
//用取值符號取值,用于賦值
@Property(name = "stringValue", value = "${stringProperty}"),
@Property(name = "integerValue", value = "${integerProperty}"),
@Property(name = "longValue", value = "${longProperty}")
})
在類名上增加注解CacheNamespaceRef,引用別的命名空間緩存,有兩種方式:
(1)通過類名路徑
@CacheNamespaceRef(name = "org.apache.ibatis.submitted.cache.PersonMapper")
(2)通過類的type
@CacheNamespaceRef(PersonMapper.class)
10.16 Arg和ConstructorArgs注解
這兩個注解一般都結合在一起使用,聲明查詢結果對應的Bean使用的構造函數(shù)和入?yún)ⅰ?/p>
10.17.1Arg注解
注解中的具體屬性如下:
//標注是否是id
boolean id() default false;
//列名
String column() default "";
//java的數(shù)據(jù)類型
Class<?> javaType() default void.class;
//jdbc中的數(shù)據(jù)類型
JdbcType jdbcType() default JdbcType.UNDEFINED;
//數(shù)據(jù)類型處理器
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
//select子句,可以復用別的sql方法獲取結果,賦值給當前查詢
//感覺這種復合查詢定位問題時可能不怎么方便
String select() default "";
//結果類型,可以填寫別的ResultMap的id的值,復用ResultMap
String resultMap() default "";
//構造函數(shù)中@Param注解中的value值
String name() default "";
//標注列前綴,在3.5.0版本中才引入的
String columnPrefix() default "";
10.17.2ConstructorArgs注解
這個注解結合Arg注解用于標注使用指定的構造函數(shù),如:
(1)簡單的指定
@ConstructorArgs({
@Arg(column = "name", name = "name"),
@Arg(id = true, column = "id", name = "id"),
@Arg(column = "team", name = "team", javaType = String.class),
})
@Select("select * from users where id = #{id}")
User mapConstructorWithParamAnnos(Integer id);
(2)復雜嵌套,配置子查詢,感覺類似于關聯(lián)查詢吧。
@Select("SELECT * FROM " +
"blog WHERE id = #{id}")
@ConstructorArgs({
@Arg(column = "id", javaType = int.class, id = true),
@Arg(column = "title", javaType = String.class),
//這里指定了一個查詢方法,且指定查詢結果中的author_id作為子查詢的入?yún)? @Arg(column = "author_id", javaType = Author.class, select = "org.apache.ibatis.binding.BoundAuthorMapper.selectAuthor"),
@Arg(column = "id", javaType = List.class, select = "selectPostsForBlog")
})
Blog selectBlogUsingConstructor(int id);
10.18 TypeDiscriminator和Case注解
類型鑒定器主要用于查詢結果判斷與映射
10.18.1 Case中的屬性
//查詢結果中的值
String value();
//java中的對象類型
Class<?> type();
//結果映射
Result[] results() default {};
//待映射對象的構造器的構造入?yún)? Arg[] constructArgs() default {};
10.18.2 TypeDiscriminator中的屬性
//列名
String column();
//java類型
Class<?> javaType() default void.class;
//jdbc中的類型
JdbcType jdbcType() default JdbcType.UNDEFINED;
//類型處理器
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
//結果情景處理
Case[] cases();
10.18.3 使用方式
@TypeDiscriminator(
// target for test (ordinal number -> Enum constant)
column = "personType", javaType = PersonType.class, typeHandler = EnumOrdinalTypeHandler.class,
// Switch using enum constant name(PERSON or EMPLOYEE) at cases attribute
cases = {
@Case(value = "PERSON", type = Person.class,
results = {@Result(property = "personType", column = "personType", typeHandler = EnumOrdinalTypeHandler.class)}) ,
@Case(value = "EMPLOYEE", type = Employee.class,
results = { @Result(property = "personType", column = "personType", typeHandler = EnumOrdinalTypeHandler.class)})
})
@Select("SELECT id, firstName, lastName, personType FROM person WHERE id = #{id}")
Person findOneUsingTypeDiscriminator(int id);
原創(chuàng)文章轉載請標明出處
更多文章請查看
http://www.canfeng.xyz