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;@BeforeClasspublic 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);}@AfterClasspublic static void release() {//释放会话资源session.close();}@Testpublic 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);
第二步:测试:
@Testpublic 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);
第二步:测试
@Testpublic 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);
第二步:测试
@Testpublic 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();
第二步:测试
@Testpublic 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);
    }
                    