1 什么叫注解
1.1 注解的作用
注解是添加在类、方法之前的以@开头的关键字。通过反射可以获得注解的内容。
1.2 注解的分类
- 元注解、基本内置注解
- 自定义注解
- 第三方注解
1.3 我们的文件结构
- 文件组成
- 模型文件包com.huang.model
- mapper映射文件包com.huang.mapper
- Demo测试文件包com.huang.test
- 配置文件

映射文件规范
在对应的映射文件里创建对应的方法。
- 在方法之前加上@insert/delete/select/update,注解的主体内容是SQL语句。
- 方法的参数表示可以往SQL语句中传入的参数
- 执行方式获取映射文件对应的映射器,执行方法。
- 映射文件
package com.huang.mapper;import java.util.List;import org.apache.ibatis.annotations.Many;import org.apache.ibatis.annotations.Delete;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Result;import org.apache.ibatis.annotations.Results;import org.apache.ibatis.annotations.Select;import org.apache.ibatis.annotations.Update;import com.huang.model.Category;public interface CategoryMapper {//注解方式的sql映射//接口中定义的成员变量,默认是用public static final 修饰的//接口中定义的方法,默认是用public abstract 修饰的//接口中定义的内部类,默认是用public static修饰的//注解中的字符串是主要的查询语句//参数表示往查询语句里传入的参数@Insert(" insert into category_ ( name ) values (#{name}) ")public int add(Category category);@Delete(" delete from category_ where id= #{id} ")public void delete(int id);@Select("select * from category_ where id= #{id} ")public Category get(int id);@Update("update category_ set name=#{name} where id=#{id} ")public int update(Category category);@Select(" select * from category_ ")public List<Category> list();//查询出id、name、包含的商品@Select(" select * from category_")@Results({@Result(property = "id", column = "id"),@Result(property = "name", column = "name"),//many属性表示一对多的关系,是另一个映射器里的查询结果//把Category的id传入到查询根据cid查询Product的方法里,获得一个列表@Result(property = "products", javaType = List.class, column = "id",many = @Many(select = "com.huang.mapper.ProductMapper.list") )})public List<Category> listWithProduct();}
- Demo文件
c. 配置文件中声明映射器//通过类对象获得映射器CategoryMapper mapper=session.getMapper(CategoryMapper.class);Category c=new Category();c.setId(2);c.setName("新的2号Category");mapper.update(c);
<mappers><!-- 此处都用注解的方式 --><mapper class="com.huang.mapper.CategoryMapper" /><mapper class="com.huang.mapper.ProductMapper" /><mapper class="com.huang.mapper.OrderMapper" /><mapper class="com.huang.mapper.OrderItemMapper" /></mappers></configuration>
2.1 insert
- 映射文件
@Insert(" insert into category_ ( name ) values (#{name}) ")public int add(Category category);
- Demo文件
System.out.println("增加:");Category c=new Category();c.setName("新的Category");mapper.add(c);
2.2 delete
- 映射文件
@Delete(" delete from category_ where id= #{id} ")public void delete(int id);
- Demo文件
System.out.println("删除1号:");mapper.delete(1);
2.3 select
- 映射文件
查询单个与查询所有
@Select("select * from category_ where id= #{id} ")public Category get(int id);@Select(" select * from category_ ")public List<Category> list();
- Demo文件
System.out.println("查询2号的名字:");Category c= mapper.get(2);System.out.println(c);System.out.println("----------");List<Category> cs=mapper.list();for(Category c:cs) {System.out.println(c);}System.out.println("----------");
2.4 update
- 映射文件
@Update("update category_ set name=#{name} where id=#{id} ")public int update(Category category);
- Demo文件
System.out.println("更新2号的名字:");Category c=new Category();c.setId(2);c.setName("新的2号Category");mapper.update(c);
3 注解方式的映射
3.1 一对多与多对一
3.1.1 E-R图模型
E-R图模型:一个商品Product对应一个种类Category,一个种类Category对应多个商品Product。
3.1.2 分析
- 从Categoy角度来看:想要表示1对多的关系,需要获得所有Product.cid(类别号)为当前Category.id的Product对象。查询多条记录。
一个Category对应多个Product,因此显示所有时要用Many注解。
- 从Product角度来看:想要表示多对1的关系,只需要查询当前cid对应Category即可。查询一条记录。
一个Product对应一个Category,因此显示所有时要用One注解。
因此:在一对多的关系中,数据库内部是用外键实现的。但在MyBatis中需要通过查询来获得。
映射文件
- CategoryMapper,这是1这一方。
@Select("select * from category_ where id= #{id} ")public Category get(int id);@Select(" select * from category_")@Results({@Result(property = "id", column = "id"),@Result(property = "name", column = "name"),//many属性表示一对多的关系,是另一个映射器里的查询结果//把Category的id传入到查询根据cid查询Product的方法里,获得一个列表@Result(property = "products", javaType = List.class, column = "id",many = @Many(select = "com.huang.mapper.ProductMapper.list") )})public List<Category> listWithProduct();
- ProductMapper,这是M这一方。
@Select("select * from product_ where cid=#{cid}")public List<Product> list(int cid);@Select("select * from product_")@Results({ @Result(property = "id", column = "id"), @Result(property = "name", column = "name"),@Result(property = "category", column = "cid", one = @One(select = "com.huang.mapper.CategoryMapper.get")) })public List<Product> listWithCategory();
- Demo文件
- 测试从1这一方
CategoryMapper mapper = session.getMapper(CategoryMapper.class);// 通过映射器进行查询List<Category> cs = mapper.listWithProduct();for (Category c : cs) {//打印类别信息System.out.println(c);List<Product> ps = c.getProducts();//打印商品信息for (Product p : ps) {System.out.println("\t"+p);}}
- 测试从M这一方
ProductMapper mapper = session.getMapper(ProductMapper.class);// 通过映射器进行查询List<Product> ps=mapper.listWithCategory();for (Product p : ps) {System.out.println(p+" 对应的分类是 \t "+ p.getCategory());}
3.2 多对多
3.2.1 E-R图模型
E-R图模型:一个商品Product对应多个订单Order,一个订单Order对应多个商品Product。通过OrderItem这个中间表来联系。
本质还是两个一对多
3.2.2 分析
- 从Product角度来讲:想要表示需要获得所有OrderItem.pid(商品号)为当前Product.id的OrderItem对象。因此OrderItemMapper中应该有根据pid查多个OrderItem的方法。
一个Product对应多个OrderItem,显示所有时要用使用了Many注解。
- 从Order角度来讲:想要表示需要获得所有OrderItem.oid(订单号)为当前Order.id的OrderItem对象。因此OrderItemMapper中应该有根据oid查多个OrderItem的方法。
一个Product对应多个OrderItem,显示所有时要用使用了Many注解。
- 从OrderItem角度来看:想要表示多对1的关系,只需要查询当前pid对应Product即可、查询当前oid对应Order即可。查询一条记录。
因此OrderItemMapper中应该有根据pid查询一个Product的方法,使用了One注解,在OrderMapper中应该有根据oid查询一个Order的方法。
- 因此多对多的关系拆成两个一对多的关系。
3.2.3 代码
- 映射文件
- ProductMapper
// 根据id查询单个Product@Select("select * from product_ where id = #{id}")public Product get(int id);@Select("select * from product_")@Results({ @Result(property = "id", column = "id"),@Result(property = "orderItems", javaType = List.class, column = "id", many = @Many(select = "com.huang.mapper.OrderItemMapper.listByProduct")) })public List<Product> listWithOrderItem();
b.OrderMapper
// 根据id查询单个Order@Select("select * from order_ where id = #{id}")public Order get(int id);@Select("select * from order_")@Results({@Result(property = "id", column = "id"),@Result(property = "orderItems", javaType = List.class, column = "id",many = @Many(select = "com.huang.mapper.OrderItemMapper.listByOrder"))})public List<Order> listWithOrderItem();
c.OrderItemMapper
//显示指定Order的id对应的所有订单条目,包含了Product对象@Select(" select * from order_item_ where oid = #{oid}")@Results({@Result(property="product",column="pid",one=@One(select="com.huang.mapper.ProductMapper.get"))})public List<OrderItem> listByOrder(int oid);//显示指定Product的id对应的所有订单条目,包含了Order对象@Select(" select * from order_item_ where pid = #{pid}")@Results({@Result(property="order",column="oid",one=@One(select="com.huang.mapper.OrderMapper.get"))})public List<OrderItem> listByProduct(int pid);
- Demo文件
- 测试Product
// 通过类对象获得映射器OrderMapper mapper = session.getMapper(OrderMapper.class);List<Order> os = mapper.listWithOrderItem();for (Order o : os) {System.out.println(o.getCode());List<OrderItem> ois = o.getOrderItems();if (null != ois) {for (OrderItem oi : ois) {System.out.format("\t%s\t%f\t%d%n", oi.getProduct().getName(), oi.getProduct().getPrice(),oi.getNumber());}}}
- 测试Order
ProductMapper mapper1 = session.getMapper(ProductMapper.class);List<Product> ps = mapper1.listWithOrderItem();for (Product p : ps) {System.out.println(p);List<OrderItem> ois = p.getOrderItems();for (OrderItem oi : ois) {System.out.format("\t%s\t%d%n", oi.getOrder().getCode(), oi.getNumber());}}
4 动态SQL语句
4.1 动态SQL语句的文件及实现思路
- 新有一个sqlProvider类,其中的方法都返回了sql语句,通过MyBatis提供的SQL语句构建器实现了快速生成sql语句。https://mybatis.org/mybatis-3/zh/statement-builders.html
- mapper文件中通过注解应用了这个类,并且制定了sql语句。
4.2 代码
- CategorySqlProvider
package com.huang.sqlProvider;import org.apache.ibatis.jdbc.SQL;public class CategorySqlProvider {//语句构建类public String list() {return new SQL().SELECT("*").FROM("category_").toString();}public String get() {return new SQL().SELECT("*").FROM("category_").WHERE("id=#{id}").toString();}public String add(){return new SQL().INSERT_INTO("category_").VALUES("name", "#{name}").toString();}public String update(){return new SQL().UPDATE("category_").SET("name=#{name}").WHERE("id=#{id}").toString();}public String delete(){return new SQL().DELETE_FROM("category_").WHERE("id=#{id}").toString();}}
- CategoryMapper
@InsertProvider(type=CategorySqlProvider.class,method="add")public int add(Category category);@DeleteProvider(type=CategorySqlProvider.class,method="delete")public void delete(int id);@SelectProvider(type=CategorySqlProvider.class,method="get")public Category get(int id);@UpdateProvider(type=CategorySqlProvider.class,method="update")public int update(Category category);@SelectProvider(type=CategorySqlProvider.class,method="list")public List<Category> list();
- Demo文件与CRUD相同。
5 总结
5.1 基本规则
- 配置文件中声明方式
<mapper class="com.huang.mapper.CategoryMapper" />
- 映射文件的命名方式模型名+mapper。
- 获取对应映射文件的映射器。
//通过类对象获得映射器CategoryMapper mapper=session.getMapper(CategoryMapper.class);
5.2 CRUD
@insert/delete/select/update注解。
5.3 一对多
1这一方用Many注解,多这一方用One注解。
- Many注解添加方式,以{}添加子注解
- Result注解中Property属性表示模型的属性,column表示sql查询语句中属性字段
- javaType为List.class表示集合类型的变量。
- Many注解指定的外部的column作为参数传入Many子注解的查询。
@Select("select * from product_")@Results({ @Result(property = "id", column = "id"),@Result(property = "orderItems", javaType = List.class, column = "id", many = @Many(select = "com.huang.mapper.OrderItemMapper.listByProduct")) })
- One注解添加方式
- One驻俄界指定的column作为参数传入One子注解的查询
@Select("select * from product_")@Results({ @Result(property = "id", column = "id"), @Result(property = "name", column = "name"),@Result(property = "category", column = "cid", one = @One(select = "com.huang.mapper.CategoryMapper.get")) })
5.4 多对多
5.5 动态SQL语句
- 先创建一个类通过SQL构建器提供一系列方法向外提供SQL语句。
- 映射文件中使用insert/delete/select/updateProvider,type属性指定上面这个类,method属性指明具体方法
