这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
上文介绍了Mybatis之使用XML实现增删改查。在Mybatis中,虽然使用XML的方式较为普遍,但是其实Mybatis也是支持使用注解来进行增删改查的,本文就来介绍一下在Mybatis中基于注解实现增删改查的方法。
Mybatis所支持的注解都在
org.apache.ibatis.annotations包中,本文只挑选常用的一些注解进行演示其使用。
| 注解 | 位置 | 与之对应的XML标签 | 描述 |
|---|---|---|---|
| @Arg | - | arg/idArg | 单参数构造方法,是 ConstructorArgs 集合的一部分。name属性用于表示构造方法中的参数名称。columnPrefix属性用于构造方法中参数也是一个POJO类时,将具有此属性值前缀的列通过声明的resultMap进行映射。 |
| @AutomapConstructor | 构造方法 | - | 用于声明自动映射的构造方法 |
| @CacheNamespace | 类 | cache | 为给定的命名空间(比如类)配置缓存。 |
| @CacheNamespaceRef | 类 | cacheRef | 参照另外一个命名空间的缓存来使用。 |
| @Case | - | case | 单独实例的值和它对应的映射。 |
| @ConstructorArgs | 方法 | constructor | 收集一组结果传递给一个结果对象的构造方法。 |
| @Delete | 方法 | delete | 代表将会被执行的 SQL 语句。 |
| @DeleteProvider | 方法 | delete | 允许构建动态 SQL |
| @Flush | 方法 | - | 如果使用了这个注解,定义在 Mapper 接口中的方法能够调用 SqlSession#flushStatements() 方法。(Mybatis 3.3及以上) |
| @Insert | 方法 | insert | 代表将会被执行的 SQL 语句。 |
| @InsertProvider | 方法 | insert | 允许构建动态 SQL |
| @Lang | 方法 | lang属性 | 配置解析SQL所需要的Driver |
| @Many | - | collection | 映射到复杂类型的集合属性。 |
| @MapKey | 方法 | - | 这是一个用在返回值为 Map 的方法上的注解。它能够将存放对象的 List 转化为 key 值为对象的某一属性的 Map。属性有: value,填入的是对象的属性名,作为 Map 的 key 值。 |
| @Mapper | 类、方法、属性、参数 | - | 用于和spring进行整合。 |
| @One | - | association | 复杂类型的单独属性值映射。 |
| @Options | 方法 | - | 映射语句的属性 |
| @Param | 参数 | - | 映射方法的形参。 |
| @Property | - | property | 指定参数值或占位值。 |
| @Result | - | result/id | 在列和属性或字段之间的单独结果映射。 |
| @ResultMap | 方法 | - | 给 @Select 或者 @SelectProvider 提供在 XML 映射中的 的id。 |
| @Results | 方法 | resultMap | 结果映射的列表 |
| @ResultType | 方法 | - | 在使用了结果处理器的情况下使用。仅在方法返回类型是 void 的情况下生效。 |
| @Select | 方法 | select | 代表将会被执行的 SQL 语句。 |
| @SelectKey | 方法 | selectKey | 功能与 selectKey 标签完全一致 |
| @SelectProvider | 方法 | select | 允许构建动态 SQL |
| @TypeDiscriminator | 方法 | discriminator | 一组实例值被用来决定结果映射的表现 |
| @Update | 方法 | update | 代表将会被执行的 SQL 语句。 |
| @UpdateProvider | 方法 | update | 允许构建动态 SQL |
准备
// 商品分类POJO
public class Category {
/**
* ID
*/
private Integer id;
/**
* 分类名称
*/
private String name;
//省略getter/setter等方法
}
// 商品POJO
public class Purchase {
/**
* ID
*/
private Integer id;
/**
* 商品名称
*/
private String name;
/**
* 商品价格
*/
private Integer price;
/**
* 商品分类
*/
private Integer category;
public Purchase() {
}
public Purchase(Integer id, String name) {
this.id = id;
this.name = name;
}
//省略getter/setter等方法
}
增加
Mapper中的方法
//Insert注解传入的参数是字符串数组,因此可以将SQL语句分解成字符串数组,也可以拼成一个字符串
// @Insert("insert into purchase (id, name, price, category) values(#{id},#{name},#{price},#{category})")
@Insert({"insert", "into purchase", " (id, name, price, category)", " values(#{id},#{name},#{price},#{category})"})
//Options注解用于插入数据后返回数据的自增ID
@Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
int insertAnnoPojo(Purchase purchase);
测试代码及结果,可以看到,刚插入的数据的id已经返回了。
@Test
public void insert() {
PurchaseMapper mapper = sqlSession.getMapper(PurchaseMapper.class);
//组装参数
Purchase purchase = new Purchase();
purchase.setName("西瓜");
purchase.setPrice(12);
purchase.setCategory(3);
mapper.insertAnnoPojo(purchase);
System.out.println(purchase);
}
DEBUG [main] - ==> Preparing: insert into purchase (id, name, price, category) values(?,?,?,?)
DEBUG [main] - ==> Parameters: null, 西瓜(String), 12(Integer), 3(Integer)
DEBUG [main] - <== Updates: 1
Purchase{id=12, name='西瓜', price=12, category=3}
查询
Mapper接口中的方法
常用注解
//使用ConstructorArgs与Arg注解,通过构造方法为POJO赋值
@Select("select id,name from purchase where id = #{id}")
@ConstructorArgs({
@Arg(column = "id", javaType = Integer.class, id = true),
@Arg(column = "name", javaType = String.class)
})
Purchase findAnnoPojo(Purchase purchase);
//使用Results与Result注解,通过结果集映射的方式为POJO赋值,这种方式一般在列名与属性名不一致的情况下使用,这里是为了做演示。
//Results注解的id是为这个结果集起一个名字,其他的查询也可以通过这个名字使用到这个结果集
@Select("select id,name from purchase where id = #{id}")
@Results(id = "purchaseMap", value = {
@Result(property = "id", column = "id", javaType = Integer.class, jdbcType = JdbcType.INTEGER, id = true),
@Result(property = "name", column = "name", javaType = String.class, jdbcType = JdbcType.VARCHAR)
})
Purchase findAnnoPojo(Purchase purchase);
//使用ResultMap注解实现结果集复用
@Select("select id,name from purchase where id = #{id}")
@ResultMap("purchaseMap")
Purchase findAnnoById(Integer id);
ResultType注解用法
// 自定义结果处理器,实现org.apache.ibatis.session.ResultHandler接口
public class PurchaseResultHandler implements ResultHandler {
List<Purchase> purchases;
public PurchaseResultHandler() {
super();
this.purchases = new ArrayList<>();
}
//实现接口中的方法,并在这里处理查询返回的数据
@Override
public void handleResult(ResultContext resultContext) {
Purchase purchase = (Purchase) resultContext.getResultObject();
purchases.add(purchase);
}
//通过get方法获取结果集
public List<Purchase> getPurchases() {
return purchases;
}
}
// Mapper中方法的写法
@Select("select id,name from purchase where id = #{id}")
@ResultType(Purchase.class)
void findAnnoById(PurchaseResultHandler resultHandler, @Param("id") Integer id);
// 测试代码
@Test
public void query() {
PurchaseResultHandler resultHandler = new PurchaseResultHandler();
mapper.findAnnoById(resultHandler, 12);
System.out.println(resultHandler.getPurchases());
}
一对一查询
- POJO类
public class PurchaseVO {
/**
* ID
*/
private Integer id;
/**
* 名称
*/
private String name;
/**
* 价格
*/
private Integer price;
/**
* 分类
*/
private Category category;
//省略getter/setter等方法
}
- Mapper接口中的方法,使用
@One注解实现
@Select("select * from purchase where id = #{id}")
@Results(id = "purchaseVoMapper", value = {
@Result(property = "category", column = "category", one = @One(select = "org.apache.ibatis.z_run.mapper.PurchaseMapper.findCategoryById"))
})
PurchaseVO findPurchaseById(Integer id);
@Select("select * from category where id = #{id}")
Category findCategoryById(Integer id);
- 测试代码及查询结果
@Test
public void query() {
PurchaseMapper mapper = sqlSession.getMapper(PurchaseMapper.class);
System.out.println(mapper.findPurchaseById(11));
}
DEBUG [main] - ==> Preparing: select * from purchase where id = ?
DEBUG [main] - ==> Parameters: 11(Integer)
DEBUG [main] - ====> Preparing: select * from category where id = ?
DEBUG [main] - ====> Parameters: 1(Integer)
DEBUG [main] - <==== Total: 1
DEBUG [main] - <== Total: 1
Purchase{id=11, name='火腿', price=3, category=Category{id=1, name='饮料'}}
一对多查询
- POJO类
public class CategoryVO {
private Integer id;
private String name;
private List<Purchase> purchases;
//省略getter/setter等方法
}
- Mapper接口中的方法
@Select("select * from category where id = #{id}")
// 这里必须要写id的映射关系,否则id值为null
@Results(id = "categoryVoMapper", value = {
@Result(property = "id", column = "id"),
@Result(property = "purchases", column = "id", many = @Many(select = "org.apache.ibatis.z_run.mapper.PurchaseMapper.findPurchaseByCategory"))
})
CategoryVO findCategoryByID(Integer id);
@Select("select * from purchase where category = #{category}")
Purchase findPurchaseByCategory(Integer category);
- 测试代码及查询结果
@Test
public void query() {
PurchaseMapper mapper = sqlSession.getMapper(PurchaseMapper.class);
System.out.println(mapper.findCategoryByID(1));
}
DEBUG [main] - ==> Preparing: select * from category where id = ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - ====> Preparing: select * from purchase where category = ?
DEBUG [main] - ====> Parameters: 1(Integer)
DEBUG [main] - <==== Total: 5
DEBUG [main] - <== Total: 1
CategoryVO{id=1, name='饮料', purchases=[Purchase{id=1, name='可乐', price=3, category=1}, Purchase{id=8, name='火腿', price=3, category=1}, Purchase{id=9, name='火腿', price=3, category=1}, Purchase{id=10, name='火腿', price=3, category=1}, Purchase{id=11, name='火腿', price=3, category=1}]}
修改
// 通常用法,使用Update注解
@Update("update purchase set price = #{price} where id = #{id}")
int updateAnnoById(@Param("id") Integer id, @Param("price") Integer price);
// 使用UpdateProvider注解,使用动态构建的SQL
@UpdateProvider(type = SqlProvider.class, method = "provideUpdate")
int updateAnnoById(@Param("id") Integer id, @Param("price") Integer price);
class SqlProvider {
public String provideUpdate(@Param("id") Integer id, @Param("price") Integer price) {
StringBuilder sql = new StringBuilder();
if (id != null) {
sql.append("update purchase ");
if (price != null) {
sql.append("set price = #{price}");
}
sql.append(" where id = #{id}");
}
return sql.toString();
}
}
删除
@Delete("delete from purchase where id = #{id}")
int deleteAnnoById(Integer id);
以上便是使用Mybatis注解完成增删改查的方法。由于在Mapper接口的方法上写SQL会显得可读性较差(特别是很复杂的SQL),因此这种方式了解即可,以后如果遇到有人使用这种方式写代码,自己能看懂就行。