上次分别总结了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之逆向工程