一、MyBatis支持的标签注解
1、增删改查
标签注解 | 作用 |
---|---|
@Update | 更新 |
@Select | 查询 |
@Insert | 插入 |
@Delete | 删除 |
2、SqlProvider
标签注解 | 作用 |
---|---|
@SelectProvider | 提供一条查询sql语句 |
@InsertProvider | 提供一条插入sql语句 |
@UpdateProvider | 提供一条更新sql语句 |
@DeleteProvider | 提供一条删除sql语句 |
3、结果映射相关
标签注解 | 作用 |
---|---|
@ResultMap | 用于引用其他的@Results的映射 |
@Results | 相当于<resultMap> 标签,用于说明映射关系 |
@Result | 相当于<resultMap> 里的<result> 标签,如果设置属性id = true则相当于标签 |
@ConstructorArgs | 相当于<constructor> 标签 |
@Arg | 相当于<constructor> 里的<arg> 标签,如果设置属性id = true则相当于标签 |
@Many | 相当于<Collection> 标签,但对于一条语句来完成N - N的情况无法处理,如果有请告诉我 |
@One | 相当于<association> 标签 |
@AutomapConstructor | 一个标记注解基本没啥用 |
4、缓存相关
标签注解 | 作用 |
---|---|
@CacheNamespace | 相当于<cache> 标签,用于设置二级缓存的属性 |
@CacheNameSpcaeRef | 共享其他二级缓存的配置与实例对象 |
@Options | 该注解有两个作用:设置语句的缓存、设置是否自增主键 |
5、主键相关
标签注解 | 作用 |
---|---|
@SelectKey | 用于设置自增主键的生成语句 |
@Options | 是否开启自增主键 |
6、鉴别器
标签注解 | 作用 |
---|---|
@TypeDiscriminator | 相当于<discrimnator> 标签 |
@Case | 相当于<case> 标签 |
7、其他
标签注解 | 作用 |
---|---|
@MapKey | 通过一个唯一值建立相关联的对象的映射 https://www.cnblogs.com/heliusKing/p/12210319.html |
@Flush | 用在批量操作中,https://blog.csdn.net/daliucheng/article/details/120251984 |
entity:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Phone implements Serializable {
private String id;
private String phone;
private PhoneTypeEnum type;
private User user;
}
--------------------------
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private String id;
private String phoneId;
private String name;
private Integer age;
private List<Phone> phone;
}
---------------------------
public enum PhoneTypeEnum {
TYPE1("中国移动"),
TYPE2("中国联通");
private String name;
PhoneTypeEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getOrdinal(){
return this.ordinal();
}
@Override
public String toString() {
return "PhoneType: {"+" name = " + getName() + " ordinal = " + getOrdinal() + "}";
}
}
二、简单的增删改查
public interface AnnocationPhoneMapper {
// -------------------------- 添加 ----------------------
@Insert(value = "insert into phone values(#{id}, #{phone}, #{type, javaType = com.bihai.mybatis_study.bean.PhoneTypeEnum, jdbcType=VARCHAR, typeHandler = org.apache.ibatis.type.EnumOrdinalTypeHandler})", databaseId = "mysql")
Boolean insert(Phone phone);
// ------------------------- 修改 -------------------------
@Update(value = "update phone set phone = #{phone} where id = #{id}", databaseId = "mysql")
@Update(value = "update phone set phone = #{phone} where id = #{id}", databaseId = "oracle")
Boolean updateById(Phone phone);
//--------------------------查询---------------------------
@Results(id = "phone",value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "phone", property = "phone"),
@Result(column = "type", property = "type", javaType = PhoneTypeEnum.class, jdbcType = JdbcType.VARCHAR, typeHandler = EnumOrdinalTypeHandler.class)
})
@Select(value = "select * from phone where id = #{value}")
Optional<Phone> selectById(String id);
//------------------------删除---------------------------------
@Delete(value = "delete from phone where id = #{id}")
Boolean deleteById(String id);
}
此处的databaseId用于指定数据库id,可以与配置文件中的databaseIdProvider 搭配使用。
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
要吐槽的是不支持集合形式的Optional,真是食之无味,弃之可惜。
三、SqlProvider
public class PhoneProvider {
public String insert(){
return "insert into phone values(#{id}, #{phone}, #{type, javaType = com.bihai.mybatis_study.bean.PhoneTypeEnum, jdbcType=VARCHAR, typeHandler = org.apache.ibatis.type.EnumOrdinalTypeHandler})";
}
public String updateById(){
return "update phone set phone = #{phone} where id = #{id}";
}
public String selectById(){
return "select * from phone where id = #{value}";
}
public String deleteById(){
return "delete from phone where id = #{id}";
}
}
public interface AnnocationPhoneMapper {
@InsertProvider(type = PhoneProvider.class, method = "insert")
Boolean insertSqlProvider(Phone phone);
@UpdateProvider(type = PhoneProvider.class, method = "updateById")
Boolean updateByIdSqlProvider(Phone phone);
@SelectProvider(type = PhoneProvider.class, method = "selectById")
@ResultMap(value = "phone")
Optional<Phone> selectByIdSqlProvider(String id);
@DeleteProvider(type = PhoneProvider.class, method = "deleteById")
Boolean deleteByIdSqlProvider(String id);
}
此处的@RsultMap里面的value引用的是前面定义的@Results里面的内容。
关于单参数、多参数情况,请参考:
mybatis 3 中 @SelectProvider的用法总结 - MyBatis中文官网
四、缓存与自增主键
此处介绍的缓存为二级缓存
1、缓存
1、再mybatis-config中开启二级缓存:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2、标注@CacheNamespace注解,相当于标签,很多都是默认配置,可以根据情况修改
@CacheNamespace()
public interface AnnocationPhoneMapper {
.....
}
3、默认情况下,对某个映射接口开启缓存,那么该接口下的查询、修改语句都会默认开启缓存,可以通过一下设置不开启当前语句的缓存
@Results(id = "phoneMap",value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "phone", property = "phone"),
@Result(column = "type", property = "type", javaType = PhoneTypeEnum.class, jdbcType = JdbcType.VARCHAR, typeHandler = EnumOrdinalTypeHandler.class)
})
@Select(value = "SELECT * FROM phone")
@Options(useCache = false) //如果不设置为false, 则默认开启缓存, 即便你没有使用@Options注解
List<Phone> selectAll();
2、自增主键
2.1 使用@Options
在此情况下需要数据库支持生成自增主键,keyColumn用于设置为那个字段生成主键,keyProperty用于设置回显的属性,设置如下:
@Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
//@InsertProvider(type = PhoneProvider.class, method = "insert")
@Insert(value = "insert into phone values(#{id}, #{phone}, #{type, javaType = com.bihai.mybatis_study.bean.PhoneTypeEnum, jdbcType=VARCHAR, typeHandler = org.apache.ibatis.type.EnumOrdinalTypeHandler})", databaseId = "mysql")
Boolean insertUseGeneratedKey(Phone phone);
测试:
/**
* 数据库自带的自增主键测试
*/
@Test
public void test4(){
try(SqlSession sqlSession = sqlSessionFactory.openSession()){
AnnocationPhoneMapper mapper = sqlSession.getMapper(AnnocationPhoneMapper.class);
Phone phone = new Phone();
phone.setPhone("13467236809");
phone.setType(PhoneTypeEnum.TYPE1);
Boolean aBoolean = mapper.insertUseGeneratedKey(phone);
System.out.println("是否插入成功:" + aBoolean + " id = " + phone.getId());
sqlSession.commit();
}
}
// 是否插入成功:true id = 23
2.2 使用@SelectKey
如果数据库不支持主键自增的话,并且你也没有传入id值,可以使用@SelectKey,但并不推荐:
@SelectKey(before = true, keyProperty = "id", keyColumn = "id",resultType = String.class,statement = {
"select CONCAT(\"NO: \",count(1)) from phone"
})
//@InsertProvider(type = PhoneProvider.class, method ="insert")
@Insert(value = "insert into phone values(#{id}, #{phone}, #{type, javaType = com.bihai.mybatis_study.bean.PhoneTypeEnum, jdbcType=VARCHAR, typeHandler = org.apache.ibatis.type.EnumOrdinalTypeHandler})", databaseId = "mysql")
Boolean insertUseSelectKey(Phone phone);
五、@MapKey
@MapKey(value = "id")
@Select(value = "SELECT * FROM phone")
@ResultMap(value = "phoneMap")
Map<String,Phone> selectAllMapKey();
六、N - 1
1、方式一
先查询出phone信息,再通过phone的Id来查询user信息
public class AnnocationPhoneMapper{
// -----------N - 1 通过电话id,查询出phone以及与之关联的user信息---------------
@Results(id = "phoneUser", value = {
@Result(id = true, property = "id", column = "id"),
@Result(property = "phone", column = "phone"),
@Result(column = "type", property = "type", javaType = PhoneTypeEnum.class, jdbcType = JdbcType.VARCHAR, typeHandler = EnumOrdinalTypeHandler.class),
@Result(property = "user", column = "id",javaType = User.class, one = @One(
fetchType = FetchType.LAZY,
select = "com.bihai.mybatis_study.mapper.AnnocationUserMapper.selectUserByPhoneId"
))
})
@Select(value = "SELECT * FROM phone")
List<Phone> selectPhoneUserAll();
}
------------------------------
public interface AnnocationUserMapper {
@Select(value = "SELECT * FROM user WHERE phoneId = #{value}")
User selectUserByPhoneId(String phoneId);
}
尽管这样的查询进行延迟加载,当加载记录列表之后立刻就遍历列表以获取嵌套的数据,就会触发所有的延迟加载查询,性能可能会变得很糟糕。
2、方式二
//-------------N - 1 通过一个查询语句----------------
@Results(id = "phoneUserOne", value = {
@Result(id = true, property = "id", column = "pId"),
@Result(property = "phone", column = "phone"),
@Result(column = "type", property = "type", javaType = PhoneTypeEnum.class, jdbcType = JdbcType.VARCHAR, typeHandler = EnumOrdinalTypeHandler.class),
@Result(id = true, column = "id", property = "user.id"),
@Result(column = "name", property = "user.name"),
@Result(column = "phoneId", property = "user.phoneId"),
@Result(column = "age", property = "user.age")
})
@Select(value = "SELECT p.id as pId, phone, type, u.* FROM phone p LEFT JOIN user u ON p.id = u.phoneId")
List<Phone> selectPhoneUserAllOne();
七、N - N
public interface AnnocationUserMapper {
// ---------------N - N 查询user、phone信息------------
@Results(id = "userPhone", value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "phoneId", property = "phoneId"),
@Result(column = "age", property = "age"),
@Result(column = "phoneId", property = "phone", javaType = List.class, many = @Many(
fetchType = FetchType.LAZY,
select = "com.bihai.mybatis_study.mapper.AnnocationPhoneMapper.selectPhoneById"
))
})
@Select(value = "select * from user")
List<User> selectUserPhoneAll();
}
----------------------------------------------
public class AnnocationPhoneMapper{
@ResultMap(value = "phoneMap")
@Select(value = "SELECT * FROM phone WHERE id = #{value}")
List<Phone> selectPhoneById(String id);
}
针对N - N的方式暂时没有找到一条语句就可以处理,并且全部使用注解的形式。