mybatis之注解

上次分别总结了mybatis基础
mybatis详解这次接着总结

注解开发

MyBatis 最初是一个 XML 驱动的框架。

配置信息是基于 XML 的,而且映射语句也是定义在 XML 中的。

随着技术的更新发展,对于开发效率要求也原来越高,特别是一些小型项目;越来越多的框架开始支持注解。

到MyBatis3时,MyBatis对注解有了完善的支持,利用注解可以在一些情况下提高开发效率

但不幸的是,Java 注解的的表达力和灵活性十分有限。尽管很多时间都花在调查、设计和试验上, 最强大的 MyBatis 映射并不能用注解来构建
常用注解

@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用

mybatis的一些配置可以去前面的文章里面找,这里直接上案例
首先创建接口:

package com.cx.mapper;

public class ProductMapper {
}

在mybatis-config.xml扫描这个包

<!--    指定要加载的映射文件-->
    <mappers>
        <package name="com.cx.mapper"/>
    </mappers>

创建实体类

public class Product {
    private int pid;
    private String name;
    private double price;
    private Date pdate;
    private String cid;
}

测试类:

private SqlSessionFactory sqlSessionFactory = null;
    @Before
    public void before() throws IOException {
        //创建
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }

mybatis注解开发会直接卸载接口里,测试在测试类写

1.select

接口:

 //根据id查询  @select演示
    @Select("select * from product where pid = #{pid}")
    @Results(id = "myResult" ,value={
            @Result(id = true,column = "pid" ,property = "pid"),
            @Result(column = "pname",property = "name")
    })
    Product selectById(int id);

测试代码:

@Test
    public void annoTest1(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = mapper.selectById(2);
        System.out.println(product);
    }
注意:
  • @Select 括号里写的是SQL语句和xml文件里写的一样,若是普通取值用#{} 如果是模糊查询一样的字符串要用单引号:‘%${}%’

  • @Results 是映射集,包含一个或多个 @Result映射,用 , 隔开
    Result里id为true代表主键,默认是flase,column是列名,property是字段名

= 当列名和字段名匹配时,注解开发是自动映射的,不匹配时要用Results注解进行定义

2. sql语句多个参数

接口方法:

//参数有多个,根据pname和price查询
    @Select("select * from product where pname like '%${pname}%' and price = #{price}")
    @Results({
            @Result(id = true,column = "pid" ,property = "pid"),
            @Result(column = "pname",property = "name")
    })
    List<Product> selectBypnameAndPrice(@Param("pname") String pname,@Param("price") Double price);

@Param(“参数名”) 当有多个参数时要用 Param注解标明每个参数的参数名

测试类:

 @Test
    public void annoTest2(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        List<Product> products = mapper.selectBypnameAndPrice("新疆", 38d);
        System.out.println(products);
    }

注意:

MyBatis的sql接收的参数只有一个无论实际传了几个

当sql语句需要多个参数时则必须将多个参数打包到一个对象中,通常是POJO或Map,上面的案例中使用了@Param注解本质就是告诉MyBatis有多个参数MyBatis会自动创建一个Map,然后将@Param的值作为Key,然后将Map传给sql,所以你也可以手动传一个Map,所以上面可以写成下面形式:

接口方法

//将参数封装到map中
    @Select("select * from product where pname like '%${pname}%' and price = #{price}")
    @Results({
            @Result(id = true ,column = "id" ,property = "id"),
            @Result(column = "pname",property = "name")
    })
    List<Product> selectBymany(Map<String,String> params);

测试代码:

@Test
    public void annoTest3(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        HashMap<String,String> map = new HashMap<>();
        map.put("pname","新疆");
        map.put("price","38d");
        List<Product> products = mapper.selectBymany(map);
        System.out.println(products);
    }

3.insert方法

接口方法:

//@insert 演示
    @Insert("insert into product values(null,#{name},#{price},#{pdate},#{cid})")
    int insertProduct(Product product);

测试代码:

@Test
    public void annoTest4(){
        //此处设置为自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = new Product();
        product.setName("周口胡辣汤");
        product.setPrice(5d);
        int i = mapper.insertProduct(product);
        System.out.println(1);
    }

注意,插入时就算实体类字段名和数据库表名不一致,也要按照实体类写,而且不用写@Results,因为这里我错了,人一天三迷糊。。。。

获取自增主键

在@select注解的下方添加@selectKey注解来完成对自增主键的获取

 @Insert("insert into product values(null,#{name},#{price},#{pdate},#{cid})")
    @SelectKey(statement = "select last_insert_id()",keyColumn = "pid",keyProperty = "pid",resultType = Integer.class,before = false)
    int insertProduct(Product product);

SelectKey 解释:

  • statement:要执行的方法
  • keyColumn:主键列名
  • keyProperty:返回对应字段名
  • resultType返回类型
  • before:插入之前返回,false代表插入之后返回

4. update

接口方法:

@Update("update product set pname = #{name},price = #{price},pdate = #{pdate},cid = #{cid} where pid = #{pid}")
    void updateByproduct(Product product);

测试代码

@Test
    public void annoTdest5(){
        //此处设置为自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = mapper.selectById(7);
        product.setName("新疆哈密瓜");
        product.setPrice(55);
        mapper.updateByproduct(product);
    }

5.delete

接口方法:

//删除演示
    @Delete("delete from product where pid = #{pid}")
    void deleteById(int id);

测试代码:

@Test
    public void annoTdest6(){
        //此处设置为自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        mapper.deleteById(12);
        sqlSession.close();
    }

6. 动态sql

动态sql指语句中包含逻辑代码,需要先运行逻辑代码,最后产生sql语句,所以需要在注解中告诉MyBatis这是一个动态sql,通过语法来指定;

若想要在sql中使用各种标签则必须添加上述根标签,否则MyBatis会将整体作为sql语句

接口方法声明:

@Select("<script>" +
            "select * from products" +
            "<where>" +
            "<if test='name != null'>" +
            "and name like '%${name}%'" +
            "</if>" +
            "</where>" +
            "</script>")
@ResultMap("myResult")
List<Product> searchByName(String name);

注解:

script:标签里面的和xml里面的动态sql一样,只是用script标签包起来了,做为标识。

ResultMap:是调用上面Results里面的内容,上面查询语句里Results设置了id,在这里调用id就可以使用value里面的内容
测试:

@Test
    public void SQLTest(){
        try (SqlSession session = factory.openSession()) {
            ProductsMappers mapper = session.getMapper(ProductsMappers.class);
            List<Product> list = mapper.searchByName("新疆");
            System.out.println(list);
        }
    }

7.结果映射(ResultMap)

上面已经说过基本用法,在这总结一下:

1.自定义字段与属性对应关系

列名与字段名不匹配,需要自定义映射:
接口:

 //根据id查询  @select演示
    @Select("select * from product where pid = #{pid}")
    @Results(id = "myResult" ,value={
            @Result(id = true,column = "pid" ,property = "pid"),
            @Result(column = "pname",property = "name")
    })
    Product selectById(int id);

测试代码:

@Test
    public void annoTest1(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = mapper.selectById(2);
        System.out.println(product);
    }

在这里插入图片描述
重复使用Results
MyBatis默认会自动映射所有字段与数据库表列相匹配的数据,另外id表示是否为主键,默认false

强调:Results可以位于对应方法的上方或下方,默认只对当前方法有效,如果需要重复使用则需要为其指定id

 @Results(id = "myResult" ,value={
            @Result(id = true,column = "pid" ,property = "pid"),
            @Result(column = "pname",property = "name")
    })//.....中间必须间隔其他方法不能立即应用到某个ResultMap
@Select("select * from product where pname like '%${pname}%' and price = #{price}")
//通过@ResultMap注解 并传入id来使用
@ResultMap("myResult")
List<Product> selectBymany(Map<String,String> params);

注意:
@Results的定义不能和使用它的@ResultMap一起出现,既然是重复使用的那我建议统一接口的最上面,
如果是当前要使用的并且要重用,直接使用Results即可,不需要在下面添加ResultMap就像下面这样:

@Select("select *from kuser where username = #{name}")
@Results(id="map1",value = {
        @Result(id = true,column = "id",property = "id"),
        @Result(column = "username",property = "name"),
})
public User selectUserByName(String name);

2.关联查询

一对一:
@One 注解(一对一)

代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。

@One 注解属性介绍:

select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。

使用格式:
    @Result(column=" ",property="",one=@One(select=""))
//一对一映射,根据订单id查询用户信息
    @Select("select * from orders where id = #{id}")
    @Results({
            @Result(id = true,column = "id" ,property = "id"),
            @Result(column = "user_id",property = "user_id"),
            @Result(column = "user_id",property = "user",one=@One(select = "selectByuser_id"))
    })
    Order selectByOrderId(int id);
    @Select("select * from user where id = #{user_id}")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "name")
    })
    User selectByuser_id(int user_id);

Result注解里:
property对应字段名,
column表明哪个列名作为参数,
one里面select对应下面的方法,即为调用下面方法按指定参数进行查询,查到后映射到指定字段上

一对多关联:

@Many 注解(多对一)

代替了<Collection>标签,是是多表查询的关键,
在注解中用来指定子查询返回对象集合。

注意:聚集元素用来处理“一对多”的关系。
需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)
但是注解中可以不定义;

使用格式:
    @Result(property="",column="",many=@Many(select=""))
//一对多查询
    @Select("select* from user where id = #{id}")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "name"),
            @Result(property = "orders",column = "id",many = @Many(select = "selectOrderByUserId"))
    })
    User selectUserById(int id);
    @Select("select * from orders where user_id = #{uid}")
    @Results({
            @Result(column = "numbers",property = "number")
    })
    List<Order> selectOrderByUserId(int uid);

一对多和一对一用法都一样,只是one注解变成了Many注解,Many注解里的select 调用一个查询方法,以id作为参数,返回的结果映射到list字段去。

一对一和一对多只能采用子查询的方式进行。
下一篇:MyBatis之逆向工程

原创文章 26 获赞 42 访问量 1304

猜你喜欢

转载自blog.csdn.net/qq_41490938/article/details/105751296