准备工作:
存在的表如下:(表名:userInfo)
代码如下:
实体类UserInfo类:
@Data public class UserInfo { private Integer id; private String username; private String password; private Integer age; private Integer gender; private String phone; private Integer deleteFlag; private Date createTime; private Date updateTime; }
UserController类:
@RequestMapping("/user") @RestController public class UserController { @Autowired private UserService userService; @RequestMapping("/getUserAll") public List<UserInfo> getUserAll() { return userService.getUserAll(); } }
UserServer类:
@Service public class UserService { @Autowired private UserInfoMapper userInfoMapper; public List<UserInfo> getUserAll() { return userInfoMapper.getUserInfoAll(); } }
UserInfoMapper接口:
@Mapper public interface UserInfoMapper { @Select("select * from userinfo") List<UserInfo> getUserInfoAll(); }
一、打印日志
在MyBatis当中,我们可以借助日志,查看SQL语句的执行、执行传递的参数以及执行结果,只需在配置文件中进行配置即可,配置内容如下:
mybatis: configuration: # 配置打印 MyBatis⽇志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
如果是application.properties,配置内容如下:
#指定mybatis输出⽇志的位置, 输出控制台 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
测试类代码如下:
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void getUserInfoAll() { System.out.println(userInfoMapper.getUserInfoAll()); } }
运行测试类,控制台比之前多出了一些内容,如下图:
二、参数传递
需求:查找id=4的用户,对应的SQL就是:select * from userinfo where id=4;
UserInfoMapper接口代码:
@Mapper public interface UserInfoMapper { @Select("select * from userinfo where id=4") List<UserInfo> queryById(); }
测试类代码如下:
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void queryById() { System.out.println(userInfoMapper.queryById()); } }
但代码也可以写成其他样子:传递参数的方式,代码如下:
@Mapper public interface UserInfoMapper { @Select("select * from userinfo") List<UserInfo> getUserInfoAll(); @Select("select * from userinfo where id=#{id}") List<UserInfo> queryById(Integer id); }
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void queryById() { System.out.println(userInfoMapper.queryById(4)); } }
执行代码,结果如下:
也可以通过@Param,设置参数的别名,如果使用@Param设置别名,#{....}里的属性名必须和@Param设置的一样,代码如下:
@Mapper public interface UserInfoMapper { @Select("select * from userinfo where id=#{userid}") List<UserInfo> queryById2(@Param("userid") Integer id); }
如果不设置别名,最好传递的参数要和SQL语句里的属性名一样。
常见错误:使用对象接受
现在表的数据如下:
我们查询gender=2的数据。
UserInfoMapper接口代码如下:
@Mapper public interface UserInfoMapper { @Select("select * from userinfo where gender=#{gender}") UserInfo queryById3(Integer gender); }
测试代码如下:
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void queryById3() { userInfoMapper.queryById3(2); } }
运行测试代码,执行结果如下:
现在更改一下数据,gender=2的数据只有一个了,如图:
在运行测试代码,没有报错,结果如下:
小结:
对于只有一个返回结果,可以使用对象或集合接收;对于有多个返回结果,只能使用集合接收。
三、增(Insert)
SQL语句:
insert into userinfo(username, password, age, gender, phone) values("zhaoliu","zhaoliu",19,1,"18700001234");
UserInfoMapper接口代码如下:
没有使用@Param注解:
@Mapper public interface UserInfoMapper { @Insert("insert into userinfo(username, password, age, gender) " + "values(#{username}, #{password}, #{age}, #{gender})") Integer insert(UserInfo userInfo); }
使用@Param注解:
@Mapper public interface UserInfoMapper { @Insert("insert into userinfo(username, password, age, gender) " + "values(#{userInfo.username}, #{userInfo.password}, #{userInfo.age}, #{userInfo.gender})") Integer insert(@Param("userInfo") UserInfo userInfo); }
测试类代码如下:
@SpringBootTest class UserInfoMapperTest { @Test void insert() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("zhaoliu"); userInfo.setPassword("123456"); userInfo.setAge(66); userInfo.setGender(2); userInfoMapper.insert(userInfo); } }
运行测试类,控制台打印内容如下:
查看userInfo表
确实多了一行,id没衔接上是因为之前我测试了一下,添加了几行数据,后面又删除了。
返回主键
想要添加主键,再加个@Options注解就好了。
UserInfoMapper接口代码:
@Mapper public interface UserInfoMapper { @Options(useGeneratedKeys = true, keyProperty = "id") @Insert("insert into userinfo(username, password, age, gender) " + "values(#{username}, #{password}, #{age}, #{gender})") Integer insert2(UserInfo userInfo); }
注解内的属性解释:
useGeneratedKeys:这会令MyBatis使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
keyProperty:指定能够唯一识别对象的属性,MyBatis会使用getGeneratedKeys的返回值或Insert语句的selectKey子元素设置它的值,默认值:未设置(unset)。
测试类代码:
@SpringBootTest class UserInfoMapperTest { @Autowired @Test void insert2() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("zhaoliu"); userInfo.setPassword("123456"); userInfo.setAge(66); userInfo.setGender(2); Integer count = userInfoMapper.insert2(userInfo); System.out.println("添加数据数:" + count + "数据ID:" + userInfo.getId()); } }
运行测试类,运行结果如下:
注意:设置 useGeneratedKeys=true之后,方法返回值依然是受影响的行数,自增id会设置在上述keyProperty指定的属性中。
四、删(Delete)
SQL:
delete from userinfo where id = 11
UserInfoMapper接口代码:
@Mapper public interface UserInfoMapper { @Delete("delete from userinfo where id = #{id}") Integer delete(Integer id); }
测试类代码:
@SpringBootTest class UserInfoMapperTest { @Test void delete() { System.out.println(userInfoMapper.delete(11)); } }
运行测试类前:
运行测试类,结果如下:
可以看到,id为11的数据被删除了。
五、改(Update)
USerInfoMapper接口类代码:
@Mapper public interface UserInfoMapper { @Update("update userinfo set username = #{username} where id = #{id}") Integer upadate(String username ,Integer id); }
测试类代码:
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void upadate() { userInfoMapper.upadate("zhouba", 10); } }
运行测试类前表的数据:
运行测试类,结果如下:
可以看到,修改成功了。
六、查(Select)
USerInfoMapper接口代码:
@Mapper public interface UserInfoMapper { @Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo") List<UserInfo> queryAllUser(); }
测试类代码:
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void queryAllUser() { System.out.println(userInfoMapper.queryAllUser()); } }
运行测试类代码,结果如下:
可以看到,有三个属性都是没有值的,为null,原因:数据库表的列名和实体类的属性名不一样,如图:
也就是说自动映射查询结果时,MyBatis会获取结果中返回的列名并在Java类中查找相同名字的属性(忽略大小写)。这意味着如果发现 ID列 和 id属性 对应时,MyBatis会把 ID列 的值赋给id属性。
因为数据库里面的表的列名 命名规范 和 Java的属性命名规范不一样,从而导致双方给同一个对象命名的名称不同,也就不能自动给它映射了,解决办法有三种:1、起别名 2、结果映射 3、开启驼峰命名
1、起别名
USerInfoMapper接口类:
@Mapper public interface UserInfoMapper { @Select("select id, username, `password`, age, gender, phone, " + "delete_flag as deleteFlag, create_time as createTime, update_time as updateTime from userinfo") List<UserInfo> queryAllUser2(); }
测试类:
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void queryAllUser2() { System.out.println(userInfoMapper.queryAllUser2()); } }
运行测试类代码,结果如下:
可以看到,现在的deleteFlag、createTime、updateTime 都不是null了。
2、结果映射
使用@Results和@Result注解,USerInfoMapper类代码如下:
@Mapper public interface UserInfoMapper { @Results({ @Result(column = "delete_flag", property = "deleteFlag"), @Result(column = "create_time", property = "createTime"), @Result(column = "update_time", property = "updateTime") }) @Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo") List<UserInfo> queryAllUser3(); }
测试类代码如下:
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void queryAllUser3() { System.out.println(userInfoMapper.queryAllUser3()); } }
运行测试类代码,结果如下:
如果希望其他SQL也可以使用该映射,就给@Results注释多加个id属性,其他SQL想使用,就加@ResultMap注解使用,代码如下:
@Mapper public interface UserInfoMapper { @Results(id = "resultMap" , value = { @Result(column = "delete_flag", property = "deleteFlag"), @Result(column = "create_time", property = "createTime"), @Result(column = "update_time", property = "updateTime") }) @Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo") List<UserInfo> queryAllUser4(); @ResultMap(value = "resultMap") @Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo") List<UserInfo> queryAllUser5(); }
使用id属性给该Results定义别名,使用@ResultMap注释来复用其他定义的ResultMap。如图:
3、开启驼峰命名(推荐)
通常数据库列使用蛇形命名发进行命名(下划线分割各个单词),而Java属性一般遵循驼峰命名法约定。为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase 设置为true。xml文件内容如下:
mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #配置打印 MyBatis⽇志 map-underscore-to-camel-case: true #自动驼峰转换
驼峰命名规则:abc_xyz => abcXyz。表中字段名:abc_xyz。类中属性名:abcXyz
现在重新使用下面代码测试,USerInfoMapper接口代码如下:
@Mapper public interface UserInfoMapper { @Select("select id, username, password, age, gender, phone, delete_flag, create_time, update_time from userinfo") List<UserInfo> queryAllUser(); }
测试类代码:
@SpringBootTest class UserInfoMapperTest { @Autowired private UserInfoMapper userInfoMapper; @Test void queryAllUser() { System.out.println(userInfoMapper.queryAllUser()); } }
运行测试类代码,结果如下:
可以看到,deleteFlag、createTime、updateTime这三个属性的值不为null,全都被赋值了。