mybatis配置数据映射的方式有哪些?
什么是MyBatis的注解方式?
MyBatis的注解方式就是将SQL语句直接写在接口上。在MyBatis注解SQL中,最基本的就是@Select、@Insert、@Update和@Delete四种。
MyBatis注解方式的优缺点
- 优点:对于需求比较简单的系统,开发效率高。
- 缺点:当SQL有变化时都需要重新编译代码,一般情况下不建议使用注解方式
2、注解实现CRUD
说明:在演示注解开发之前,为了避免和之前的映射文件混淆,所以可以将之前书写的代码放到一个新的工程中,删除映射文件即可。
一个功能不能同时用xml和注解方式,要二选一。不同的功能,可以自由选择xml或者注解
2.0、CRUD相关注解
【注解】
@Insert:保存
Value:sql语句(和xml的配置方式一模一样)
@Update:更新
Value:sql语句
@Delete: 删除
Value:sql语句
@Select: 查询
Value:sql语句
@Options:可选配置(获取主键)
userGeneratedKeys:开关,值为true表示可以获取主键 相当于select last_insert_id()
keyProperty :对象属性
keyColumn : 列名
【使用方式】
【第一步】将mybatis全局配置文件mybatis-config.xml中的mapper路径改为包扫描或者指定class路径;
<configuration>
...
<mappers>
<!--接口所在包-->
<package name="com.itheima.dao"/>
</mappers>
</configuration>
2.1、新增
目标:使用注解@Insert
的方式新增数据
步骤:
第一步:UserMapper接口中新增用户方法上面编写注解; 第二步:测试
实现:
第一步:在UserMapper接口中的saveUser()方法上面添加@Insert
注解,并设置该注解的value属性值为具体的SQL语句;
public interface UserMapper {
//1、新增数据 #{userName} 这里的userName是方法saveUser(User user)参数User类的成员变量
@Insert("INSERT INTO tb_user VALUES(NULL,#{userName},#{password},#{name},#{age},#{sex})")
void saveUser(User user);
}
第二步:测试
在UserMapperTest类下面对save方法进行测试:
import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisTest01 {
public static UserMapper mapper;
public static SqlSession session;
@BeforeClass
public static void init() throws IOException {
// 所有测试方法执行前初始化
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession(true); //设置事务为自动提交
mapper = session.getMapper(UserMapper.class);
}
@AfterClass
public static void release() {
//释放会话资源
session.close();
}
@Test
public void saveUser(){
User user = new User();
user.setUserName("大圣");
user.setAge(500);
user.setName("孙悟空");
user.setPassword("1234");
user.setSex(1);
userMapper.saveUser(user);
}
}
小结:
新增数据的注解为:@Insert
,作用等同于xml映射文件中的<insert>
具体使用时,需要给其value属性设置具体的SQL。
新增数据时id回填(自增主键回填)了解
目标:使用注解完成数据新增,新增成功后返回数据的主键id值
步骤:
1、在新增数据注解 @Insert下面,添加@Options; 2、在Options注解中,设置useGeneratedKeys值为true,keyProperty为id,keyColumn id;
实现:
第一步:在新增数据注解 @Insert下面,添加@Options,设置useGeneratedKeys值为true,keyProperty为id,keyColumn 为id;
//1、新增数据 #{userName} 这里的userName是方法saveUser(User user)参数User类的成员变量
@Insert("INSERT INTO tb_user VALUES(NULL,#{userName},#{password},#{name},#{age},#{sex})")
@Options(useGeneratedKeys = true,keyColumn = "id",keyProperty = "id")
int saveUser(User user);
第二步:测试:
@Test
public void saveUserTest() {
User user = new User();
user.setId(null); //主键自增
user.setUserName("大圣");
user.setPassword("12345");
user.setName("孙悟空");
user.setSex(2);
mapper.saveUser(user);
System.out.println("user = " + user);
}
User{id=15, userName=’大圣’, password=’12345’, name=’孙悟空’, age=null, sex=2}
@Options(useGeneratedKeys = true,keyColumn = “id”,keyProperty = “id”)
2.2、删除
目标:使用注解@Delete
删除id值为1的数据
步骤:
第一步:在根据id删除数据的方法上面编写注解@Delete; 第二步:测试
实现:
第一步:在UserMapper接口中的deleteUserById方法上编写@Delete
,并设置其value属性值为具体的删除SQL;
/*
2.根据id删除用户
*/
@Delete("delete from tb_user where id=#{id}")
int deleteUserById(Long id);
第二步:测试
@Test
public void deleteUserById(){
userMapper.deleteUserById(1L);
}
小结:
删除数据的注解:@Delete
,作用等同于映射文件中的<delete>
,具体使用时,需要设置其value属性值为具体的删除SQL;
2.3、修改
目标:修改id为1的用户的数据
步骤:
第一步:在根据id修改用户数据方法上面添加注解@Update,然后在其value属性值中编写具体的SQL; 第二步:测试
实现:
第一步:在UserMapper接口的updateUser方法上添加注解:@Update
,然后将其value属性值设置成update的SQL;
/**
* 3.修改用户数据
* @param user
*/
@Update("UPDATE tb_user SET user_name=#{userName}, password=#{password} ,name=#{name} ,age=#{age},sex=#{sex} where id=#{id}")
int updateUser(User user);
第二步:测试
@Test
public void updateUser(){
User user = new User();
user.setId(1L);
user.setUserName("柳岩");
user.setSex(0);
user.setPassword("3456");
user.setName("岩岩");
user.setAge(20);
userMapper.updateUser(user);
}
小结:修改数据的注解:@Update
,作用等同于映射文件中的<update>
。
2.4、查询
目标:使用注解查询所有的用户数据
步骤:
第一步:在接口中查询所有的用户数据的方法上面添加注解:@Select,然后设置其value属性值为具体的SQL查询语句; 第二步:测试
实现:
第一步:在UserMapper接口的queryAllUsers方法上添加注解:@Select
,然后设置其value属性值为具体的查询SQL;
/*
* 4.查询所有用户数据
*/
@Select("SELECT * FROM tb_user")
List<User> queryAllUsers();
第二步:测试
@Test
public void queryAllUsers(){
List<User> list = userMapper.queryAllUsers();
System.out.println("list = " + list);
}
小结:
查询数据注解:@Select
,作用等同于映射文件中的<select>
标签。
3、注解实现别名映射
根据之前的学习,如果数据表的列名和pojo实体类的属性名不一致,会导致数据表的数据无法封装到实体类属性值中,对此我们又如下解决方案:
【1】查询的时候给列起别名,别名和实体类的属性名一致
select user_name as userName from tb_user where id =1;
【2】在mybatis的核心配置文件中按照如下配置:
<settings>
<!--开启驼峰自动映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
【3】在映射文件中,我们可以通过在ResultMap中,通过result标签中,给指定的column映射到实体类中指定的属性上。
<resultMap id="orderAndUserResultRelative" type="Order">
<result column="user_name" property="userName"/>
</resultMap>
而在注解中也有相应的解决方案:这里就必须使用注解:@Results
@Results
注解相当于之前映射文件中的ResultMap,该注解如下:
public @interface Results {
Result[] value() default {};
}
我们发现value属于Result数组类型,而Result属于一个注解,注解的属性如下:
public @interface Result {
//对应数据表的列
String column() default "";
//对应pojo类的属性
String property() default "";
//javaType:返回的对象类型
Class<?> javaType() default void.class;
//one: 一对一配置
One one() default @One;
//many: 一对多配置
Many many() default @Many;
}
需求:查询指定id的用户。使用注解映射用户名字段。
为了演示pojo属性名和表中字段名不一样,导致自动映射失败的情况。我们修改表中字段名,让表中用户名字段名和pojo中用户名的属性名不一样,且没有驼峰和经典下划线映射关系。
实现:
第一步:在接口中查询方法上面添加注解:@Results
,然后通过@Result
完成字段的别名和实体类的属性名之间的映射配置;
说明:这里我们使用之前的查询所用用户方法即可,也可以在接口中在定义一个根据id查询用户的方法。
/*
根据id查询用户
*/
@Results({
@Result(column = "user_name11", property = "userName"),
})
@Select("select * from tb_user where id=#{id}")
User selectById(Long id);
第二步:测试
@Test
public void selectById(){
User user = userMapper.selectById(1L);
System.out.println("user = " + user);
}
【结果】
user = User{id=1, userName=’zhangsan’, password=’123456’, name=’张三’, age=30, sex=1}
小结:给别名映射到实体类中可以通过添加注解:@Results
中的 @Result
实现;
4 动态sql(理解)
【需求】:查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户。
正常的sql语句:查询男性并且用户名中包含zhang
select * from tb_user where sex = "男" and user_name like '%zhang%'
select * from tb_user where sex = "男"
实现需求时还要判断用户是否输入用户名来做不同的查询要求,而这里似乎没有办法判断是否输入了用户名,因此可以考虑使用动态sql来完成这个功能。<br /> 上述动态sql语句部分: and user_name like '%zhang%'
注解开发时,Mybatis给我们提供了三种编写动态sql的方式:
方式1: 脚本标签 (自己课下学习,课上不讲解)
在接口上添加: <script></script>
标签,标签体中编写sql语句,sql语句与之前配置文件中的一致
//【需求】:查询**男性**用户,**如果输入了用户名,按用户名模糊查询**,如果**没有输入用户名,就查询所有男性用户**。
@Select("<script>select * from tb_user where sex=#{sex} <if test=\"username!=null and username.trim()!=''\">and user_name like concat('%',#{username},'%')</if></script>")
List<User> queryUsersBySexOrUsername(@Param("sex") String sex,@Param("username") String username);
说明:这种方式在写法上面和 XML 中的写法是一样,支持 XML 的动态SQL语法,可以在上面的字符串中写 **<foreach>**
等 标签的语法。
测试类:
@Test
public void queryUsersBySexOrUsername() {
List<User> list = mapper.queryUsersBySexOrUsername("男", "lisi");
System.out.println("list = " + list);
}
方式2:_@_SelectProvider
使用 _@_SelectProvider 注解,注解中的type 参数是提供构建 SQL 的类,method 是构建 SQL 的方法。构建 SQL 的方法的参数要和接口的参数一致,并且多个参数要使用命名参数。
接口:
@SelectProvider(type= ProviderUtils.class,method = "queryUsersBySexOrUsernameSQL")
List<User> queryUsersBySexOrUsername(@Param("sex") String sex,@Param("username") String username);
动态sql生成类
import org.apache.ibatis.annotations.Param;
public class ProviderUtils {
public String queryUsersBySexOrUsernameSQL(@Param("sex") String sex, @Param("username") String username){
String sql = "select * from tb_user where sex = #{sex}";
if (username!=null && !"".equals(username)){
sql += " and user_name like concat('%',#{username},'%')";
}
return sql;
}
}
测试类:
@Test
public void queryUsersBySexOrUsername() {
List<User> list = mapper.queryUsersBySexOrUsername("男", "lisi");
System.out.println("list = " + list);
}
方式3: _@_SelectProvider
上一中方式时直接拼接字符串,容易出错。比如拼接的过程中少个空格就会出问题。在生成SQL时,也可以使用 Mybatis 提供的org.apache.ibatis.jdbc.SQL
类,可以很方便我们生成SQL,如下:
public class ProviderUtils {
public String queryUsersBySexOrUsernameSQL2(@Param("sex") String sex, @Param("username") String username) {
//借助mybatis提供的一个对象:SQL
//创建SQL对象
SQL sql = new SQL();
//链式编程,每个方法返回值都是SQL类对象
sql.SELECT("*").FROM("tb_user").WHERE("sex = #{sex}");
//判断用户是否为空,不为空就继续链式编程,即继续拼接
if(username != null && !"".equals(username)){
sql.WHERE("user_name like concat('%',#{username},'%')");
}
//SELECT * FROM user WHERE (sex=? AND user_name like concat('%',?,'%'))
//转换为字符串并返回
return sql.toString();
}
}
接口方法使用注解 _@_SelectProvider 引用工具类中的方法
@SelectProvider(type= ProviderUtils.class,method = "queryUsersBySexOrUsernameSQL2")
List<User> queryUsersBySexOrUsername(@Param("sex") String sex,@Param("username") String username);
测试类:
@Test
public void queryUsersBySexOrUsername() {
List<User> list = mapper.queryUsersBySexOrUsername("男", "lisi");
System.out.println("list = " + list);
}