1 什么叫注解

1.1 注解的作用

注解是添加在类、方法之前的以@开头的关键字。通过反射可以获得注解的内容。

1.2 注解的分类

  1. 元注解、基本内置注解
  2. 自定义注解
  3. 第三方注解

我们这里用的就是第三方(MyBatis提供的)注解

1.3 我们的文件结构

  1. 文件组成
    1. 模型文件包com.huang.model
    2. mapper映射文件包com.huang.mapper
    3. Demo测试文件包com.huang.test
    4. 配置文件

图片.png

  1. 映射文件规范

    1. 映射文件取名:模型名+mapper
    2. 同一个映射文件对应的是对同一个表的操作。

      2 CRUD的注解方式

      2.0 基本语法

  2. 在对应的映射文件里创建对应的方法。

  3. 在方法之前加上@insert/delete/select/update,注解的主体内容是SQL语句。
  4. 方法的参数表示可以往SQL语句中传入的参数
  5. 执行方式获取映射文件对应的映射器,执行方法。
    1. 映射文件
  1. package com.huang.mapper;
  2. import java.util.List;
  3. import org.apache.ibatis.annotations.Many;
  4. import org.apache.ibatis.annotations.Delete;
  5. import org.apache.ibatis.annotations.Insert;
  6. import org.apache.ibatis.annotations.Result;
  7. import org.apache.ibatis.annotations.Results;
  8. import org.apache.ibatis.annotations.Select;
  9. import org.apache.ibatis.annotations.Update;
  10. import com.huang.model.Category;
  11. public interface CategoryMapper {
  12. //注解方式的sql映射
  13. //接口中定义的成员变量,默认是用public static final 修饰的
  14. //接口中定义的方法,默认是用public abstract 修饰的
  15. //接口中定义的内部类,默认是用public static修饰的
  16. //注解中的字符串是主要的查询语句
  17. //参数表示往查询语句里传入的参数
  18. @Insert(" insert into category_ ( name ) values (#{name}) ")
  19. public int add(Category category);
  20. @Delete(" delete from category_ where id= #{id} ")
  21. public void delete(int id);
  22. @Select("select * from category_ where id= #{id} ")
  23. public Category get(int id);
  24. @Update("update category_ set name=#{name} where id=#{id} ")
  25. public int update(Category category);
  26. @Select(" select * from category_ ")
  27. public List<Category> list();
  28. //查询出id、name、包含的商品
  29. @Select(" select * from category_")
  30. @Results({
  31. @Result(property = "id", column = "id"),
  32. @Result(property = "name", column = "name"),
  33. //many属性表示一对多的关系,是另一个映射器里的查询结果
  34. //把Category的id传入到查询根据cid查询Product的方法里,获得一个列表
  35. @Result(property = "products", javaType = List.class, column = "id",
  36. many = @Many(select = "com.huang.mapper.ProductMapper.list") )
  37. })
  38. public List<Category> listWithProduct();
  39. }
  1. Demo文件
    1. //通过类对象获得映射器
    2. CategoryMapper mapper=session.getMapper(CategoryMapper.class);
    3. Category c=new Category();
    4. c.setId(2);
    5. c.setName("新的2号Category");
    6. mapper.update(c);
    c. 配置文件中声明映射器
  1. <mappers>
  2. <!-- 此处都用注解的方式 -->
  3. <mapper class="com.huang.mapper.CategoryMapper" />
  4. <mapper class="com.huang.mapper.ProductMapper" />
  5. <mapper class="com.huang.mapper.OrderMapper" />
  6. <mapper class="com.huang.mapper.OrderItemMapper" />
  7. </mappers>
  8. </configuration>

2.1 insert

  1. 映射文件
  1. @Insert(" insert into category_ ( name ) values (#{name}) ")
  2. public int add(Category category);
  1. Demo文件
  1. System.out.println("增加:");
  2. Category c=new Category();
  3. c.setName("新的Category");
  4. mapper.add(c);

2.2 delete

  1. 映射文件
  1. @Delete(" delete from category_ where id= #{id} ")
  2. public void delete(int id);
  1. Demo文件
  1. System.out.println("删除1号:");
  2. mapper.delete(1);

2.3 select

  1. 映射文件

查询单个与查询所有

  1. @Select("select * from category_ where id= #{id} ")
  2. public Category get(int id);
  3. @Select(" select * from category_ ")
  4. public List<Category> list();
  1. Demo文件
  1. System.out.println("查询2号的名字:");
  2. Category c= mapper.get(2);
  3. System.out.println(c);
  4. System.out.println("----------");
  5. List<Category> cs=mapper.list();
  6. for(Category c:cs) {
  7. System.out.println(c);
  8. }
  9. System.out.println("----------");

2.4 update

  1. 映射文件
  1. @Update("update category_ set name=#{name} where id=#{id} ")
  2. public int update(Category category);
  1. Demo文件
  1. System.out.println("更新2号的名字:");
  2. Category c=new Category();
  3. c.setId(2);
  4. c.setName("新的2号Category");
  5. mapper.update(c);

3 注解方式的映射

3.1 一对多与多对一

3.1.1 E-R图模型

E-R图模型:一个商品Product对应一个种类Category,一个种类Category对应多个商品Product。图片.png

3.1.2 分析

  1. 从Categoy角度来看:想要表示1对多的关系,需要获得所有Product.cid(类别号)为当前Category.id的Product对象。查询多条记录。

一个Category对应多个Product,因此显示所有时要用Many注解。

  1. 从Product角度来看:想要表示多对1的关系,只需要查询当前cid对应Category即可。查询一条记录。

一个Product对应一个Category,因此显示所有时要用One注解。

  1. 因此:在一对多的关系中,数据库内部是用外键实现的。但在MyBatis中需要通过查询来获得。

    1. 1这一方应该提供根据关联属性cid查单条记录的方法getBycid、显示时用Many注解。
    2. M这一方应该提供根据管理属性cid查多条记录的方法listBycid,显示时用One注解。

      3.1.3 代码

  2. 映射文件

    1. CategoryMapper,这是1这一方。
  1. @Select("select * from category_ where id= #{id} ")
  2. public Category get(int id);
  3. @Select(" select * from category_")
  4. @Results({
  5. @Result(property = "id", column = "id"),
  6. @Result(property = "name", column = "name"),
  7. //many属性表示一对多的关系,是另一个映射器里的查询结果
  8. //把Category的id传入到查询根据cid查询Product的方法里,获得一个列表
  9. @Result(property = "products", javaType = List.class, column = "id",
  10. many = @Many(select = "com.huang.mapper.ProductMapper.list") )
  11. })
  12. public List<Category> listWithProduct();
  1. ProductMapper,这是M这一方。
  1. @Select("select * from product_ where cid=#{cid}")
  2. public List<Product> list(int cid);
  3. @Select("select * from product_")
  4. @Results({ @Result(property = "id", column = "id"), @Result(property = "name", column = "name"),
  5. @Result(property = "category", column = "cid", one = @One(select = "com.huang.mapper.CategoryMapper.get")) })
  6. public List<Product> listWithCategory();
  1. Demo文件
    1. 测试从1这一方
  1. CategoryMapper mapper = session.getMapper(CategoryMapper.class);
  2. // 通过映射器进行查询
  3. List<Category> cs = mapper.listWithProduct();
  4. for (Category c : cs) {
  5. //打印类别信息
  6. System.out.println(c);
  7. List<Product> ps = c.getProducts();
  8. //打印商品信息
  9. for (Product p : ps) {
  10. System.out.println("\t"+p);
  11. }
  12. }
  1. 测试从M这一方
  1. ProductMapper mapper = session.getMapper(ProductMapper.class);
  2. // 通过映射器进行查询
  3. List<Product> ps=mapper.listWithCategory();
  4. for (Product p : ps) {
  5. System.out.println(p+" 对应的分类是 \t "+ p.getCategory());
  6. }

3.2 多对多

3.2.1 E-R图模型

E-R图模型:一个商品Product对应多个订单Order,一个订单Order对应多个商品Product。通过OrderItem这个中间表来联系。
图片.png
本质还是两个一对多
图片.png

3.2.2 分析

  1. 从Product角度来讲:想要表示需要获得所有OrderItem.pid(商品号)为当前Product.id的OrderItem对象。因此OrderItemMapper中应该有根据pid查多个OrderItem的方法。

一个Product对应多个OrderItem,显示所有时要用使用了Many注解。

  1. 从Order角度来讲:想要表示需要获得所有OrderItem.oid(订单号)为当前Order.id的OrderItem对象。因此OrderItemMapper中应该有根据oid查多个OrderItem的方法。

一个Product对应多个OrderItem,显示所有时要用使用了Many注解。

  1. 从OrderItem角度来看:想要表示多对1的关系,只需要查询当前pid对应Product即可、查询当前oid对应Order即可。查询一条记录。

因此OrderItemMapper中应该有根据pid查询一个Product的方法,使用了One注解,在OrderMapper中应该有根据oid查询一个Order的方法。

  1. 因此多对多的关系拆成两个一对多的关系。

3.2.3 代码

  1. 映射文件
    1. ProductMapper
  1. // 根据id查询单个Product
  2. @Select("select * from product_ where id = #{id}")
  3. public Product get(int id);
  4. @Select("select * from product_")
  5. @Results({ @Result(property = "id", column = "id"),
  6. @Result(property = "orderItems", javaType = List.class, column = "id", many = @Many(select = "com.huang.mapper.OrderItemMapper.listByProduct")) })
  7. public List<Product> listWithOrderItem();
  1. b.OrderMapper
  1. // 根据id查询单个Order
  2. @Select("select * from order_ where id = #{id}")
  3. public Order get(int id);
  4. @Select("select * from order_")
  5. @Results({
  6. @Result(property = "id", column = "id"),
  7. @Result(property = "orderItems", javaType = List.class, column = "id",
  8. many = @Many(select = "com.huang.mapper.OrderItemMapper.listByOrder"))
  9. })
  10. public List<Order> listWithOrderItem();

c.OrderItemMapper

  1. //显示指定Order的id对应的所有订单条目,包含了Product对象
  2. @Select(" select * from order_item_ where oid = #{oid}")
  3. @Results({
  4. @Result(property="product",column="pid",one=@One(select="com.huang.mapper.ProductMapper.get"))
  5. })
  6. public List<OrderItem> listByOrder(int oid);
  7. //显示指定Product的id对应的所有订单条目,包含了Order对象
  8. @Select(" select * from order_item_ where pid = #{pid}")
  9. @Results({
  10. @Result(property="order",column="oid",one=@One(select="com.huang.mapper.OrderMapper.get"))
  11. })
  12. public List<OrderItem> listByProduct(int pid);
  1. Demo文件
    1. 测试Product
  1. // 通过类对象获得映射器
  2. OrderMapper mapper = session.getMapper(OrderMapper.class);
  3. List<Order> os = mapper.listWithOrderItem();
  4. for (Order o : os) {
  5. System.out.println(o.getCode());
  6. List<OrderItem> ois = o.getOrderItems();
  7. if (null != ois) {
  8. for (OrderItem oi : ois) {
  9. System.out.format("\t%s\t%f\t%d%n", oi.getProduct().getName(), oi.getProduct().getPrice(),
  10. oi.getNumber());
  11. }
  12. }
  13. }
  1. 测试Order
  1. ProductMapper mapper1 = session.getMapper(ProductMapper.class);
  2. List<Product> ps = mapper1.listWithOrderItem();
  3. for (Product p : ps) {
  4. System.out.println(p);
  5. List<OrderItem> ois = p.getOrderItems();
  6. for (OrderItem oi : ois) {
  7. System.out.format("\t%s\t%d%n", oi.getOrder().getCode(), oi.getNumber());
  8. }
  9. }

4 动态SQL语句

4.1 动态SQL语句的文件及实现思路

  1. 新有一个sqlProvider类,其中的方法都返回了sql语句,通过MyBatis提供的SQL语句构建器实现了快速生成sql语句。https://mybatis.org/mybatis-3/zh/statement-builders.html
  2. mapper文件中通过注解应用了这个类,并且制定了sql语句。

图片.png

4.2 代码

  1. CategorySqlProvider
  1. package com.huang.sqlProvider;
  2. import org.apache.ibatis.jdbc.SQL;
  3. public class CategorySqlProvider {
  4. //语句构建类
  5. public String list() {
  6. return new SQL()
  7. .SELECT("*")
  8. .FROM("category_")
  9. .toString();
  10. }
  11. public String get() {
  12. return new SQL()
  13. .SELECT("*")
  14. .FROM("category_")
  15. .WHERE("id=#{id}")
  16. .toString();
  17. }
  18. public String add(){
  19. return new SQL()
  20. .INSERT_INTO("category_")
  21. .VALUES("name", "#{name}")
  22. .toString();
  23. }
  24. public String update(){
  25. return new SQL()
  26. .UPDATE("category_")
  27. .SET("name=#{name}")
  28. .WHERE("id=#{id}")
  29. .toString();
  30. }
  31. public String delete(){
  32. return new SQL()
  33. .DELETE_FROM("category_")
  34. .WHERE("id=#{id}")
  35. .toString();
  36. }
  37. }
  1. CategoryMapper
  1. @InsertProvider(type=CategorySqlProvider.class,method="add")
  2. public int add(Category category);
  3. @DeleteProvider(type=CategorySqlProvider.class,method="delete")
  4. public void delete(int id);
  5. @SelectProvider(type=CategorySqlProvider.class,method="get")
  6. public Category get(int id);
  7. @UpdateProvider(type=CategorySqlProvider.class,method="update")
  8. public int update(Category category);
  9. @SelectProvider(type=CategorySqlProvider.class,method="list")
  10. public List<Category> list();
  1. Demo文件与CRUD相同。

5 总结

5.1 基本规则

  1. 配置文件中声明方式
  1. <mapper class="com.huang.mapper.CategoryMapper" />
  1. 映射文件的命名方式模型名+mapper。
  2. 获取对应映射文件的映射器。
  1. //通过类对象获得映射器
  2. CategoryMapper mapper=session.getMapper(CategoryMapper.class);

5.2 CRUD

  1. @insert/delete/select/update注解。

    5.3 一对多

  2. 1这一方用Many注解,多这一方用One注解。

  3. Many注解添加方式,以{}添加子注解
    1. Result注解中Property属性表示模型的属性,column表示sql查询语句中属性字段
    2. javaType为List.class表示集合类型的变量。
    3. Many注解指定的外部的column作为参数传入Many子注解的查询。
  1. @Select("select * from product_")
  2. @Results({ @Result(property = "id", column = "id"),
  3. @Result(property = "orderItems", javaType = List.class, column = "id", many = @Many(select = "com.huang.mapper.OrderItemMapper.listByProduct")) })
  1. One注解添加方式
    1. One驻俄界指定的column作为参数传入One子注解的查询
  1. @Select("select * from product_")
  2. @Results({ @Result(property = "id", column = "id"), @Result(property = "name", column = "name"),
  3. @Result(property = "category", column = "cid", one = @One(select = "com.huang.mapper.CategoryMapper.get")) })

5.4 多对多

拆解成两个1对多。

5.5 动态SQL语句

  1. 先创建一个类通过SQL构建器提供一系列方法向外提供SQL语句。
  2. 映射文件中使用insert/delete/select/updateProvider,type属性指定上面这个类,method属性指明具体方法