MyBatis是支持定制化SQL、存储过程以及高级映射的优秀持久层框架。MyBatis避免了几乎所有JDBC代码的手动设置参数已经获取结果集。MyBatis可以对配置和原生Map使用简单的XML或注解,将接口和Java的POJOs(普通的Java对象)映射成数据库中的记录。
MyBatis的引入和配置
在maven的pom.xml中引入:
junit
junit
4.12
test
org.mybatis
mybatis
3.5.1
mysql
mysql-connector-java
8.0.15
然后在resource中新建dbconfig.properties和mybatis-config.xml文件:
dbconfig.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/Dane?characterEncoding=utf-8
username=root
password=root
mybatis-config.xml文件:
这样就引入了MyBatis,其中mappers是与我们开发的userMapper.xml是与我们开发的bean对应,下面会举例。
MyBatis的增删改查
引入和配置了MyBatis后,先简单的封装下MyBatis,把通用操作简单封装:
这里有几个注意的点,如果你的mybatis-config.xml文件不是放在resource下,那就必须给它全路径,获取SqlSession时,mybatis默认执行SQL后是不自动提交的,需要自动提交需要sqlSessionFactory.openSession(true):
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
public static SqlSession getSqlSession(boolean autoCommit){
return sqlSessionFactory.openSession(autoCommit);
}
public static void close(SqlSession sqlSession){
if(sqlSession != null){
sqlSession.close();
}
}
}
然后写个User对象:
public class User {
private String id;
private String name;
private String password;
private String account;
...
}
接着在resource中新建mapper文件夹,并在里面创建UserMapper.xml:
parameterType为传入参数类型,resultType为返回类型
然后在mybatis-config.xml配置下:
接下来可以进行增删改查了:
sqlSession进行增删改查时,参数一对应的是UserMapper.xml中的命名空间和id,如查dane.selectUser
新建IUserDao以及实现类UserDaoImpl:
public interface IUserDao {
public List selectUsers();
public void insertUsers(User user);
public void updateUsers(User user);
public void deleteUsers(int id);
}
public class UserDaoImpl implements IUserDao {
public List selectUsers() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
List users = sqlSession.selectList("dane.selectUser");
sqlSession.commit();;
MyBatisUtil.close(sqlSession);
return users;
}
public void insertUsers(User user) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
sqlSession.insert("dane.insertUser",user);
sqlSession.commit();;
MyBatisUtil.close(sqlSession);
}
public void updateUsers(User user) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
sqlSession.update("dane.updateUser",user);
sqlSession.commit();
MyBatisUtil.close(sqlSession);
}
public void deleteUsers(int id) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
sqlSession.delete("dane.deleteUser",id);
sqlSession.commit();
MyBatisUtil.close(sqlSession);
}
然后进行增删改查测试
public class MyBatisTest {
@Test
public void selectUser(){
IUserDao userDao = new UserDaoImpl();
List users = userDao.selectUsers();
for (User user : users) {
System.out.println(user.getId());
System.out.println(user.getName());
System.out.println(user.getAccount());
System.out.println(user.getPassword());
}
}
@Test
public void insertUser(){
IUserDao userDao = new UserDaoImpl();
User user = new User();
user.setAccount("Dane小号");
user.setPassword("123456");
user.setName("Dane小号");
userDao.insertUsers(user);
}
@Test
public void updateUser(){
IUserDao userDao = new UserDaoImpl();
User user=new User();
user.setId(2);
user.setName("dane6666");
userDao.updateUsers(user);
}
@Test
public void deleteUser(){
IUserDao userDao = new UserDaoImpl();
userDao.deleteUsers(2);
}
}
Mybatis Mapper代理
在上面的例子中,我们需要自己实现IUserDao,使用Mapper代理,可以无需自己实现。
首先,看修改后的UserMapper.xml,命名空间必须是IUserDao的引用路径,每个select的id必须是IUserDao的方法,包括参数要一一对应。
然后看下使用,查询为例:
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
List users = userDao.selectUsers();
for (User user : users) {
System.out.println(user.getId());
System.out.println(user.getName());
System.out.println(user.getAccount());
System.out.println(user.getPassword());
}
MyBatisUtil.close(sqlSession);
Mybatis配置Log框架
首先要了解下slf4j日志框架并没真正的实现日志记录,而是一个日志标准或者说是抽象,它提供日志接口和提供获取具体日志对象的方法,所以真正实现日志的还要靠log4j等。
在Mybatis中只需要想pom.xml引入并在resource配置log4j.properties即可:
org.slf4j
slf4j-api
1.7.25
log4j
log4j
1.2.17
org.slf4j
slf4j-log4j12
1.7.25
log4j.properties
log4j.rootLogger=debug, stdout, R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=hx.log
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
log4j.logger.com.codefutures=DEBUG
然后运行代码,会有如下图:
使用MyBatis注解的方式
上面的SQL语句是放在UserMapper.xml文件中,MyBatis也可以使用注解的方式:
public interface IUserDao2 {
@Select(" select * from User")
public List selectUsers();
@Insert("insert into user(account,password,name) values (#{account},#{password},#{name})")
public void insertUsers(User user);
@Update("update user set name = #{name} where id = #{id}")
public void updateUsers(User user);
@Delete("delete from User where id = #{id}")
public void deleteUsers(int id);
}
然后在mybatis-config.xml中配置,注意是class
然后就可以测试啦,查询为例:
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
IUserDao2 userDao = sqlSession.getMapper(IUserDao2.class);
List users = userDao.selectUsers();
for (User user : users) {
System.out.println(user.getId());
System.out.println(user.getName());
System.out.println(user.getAccount());
System.out.println(user.getPassword());
}
MyBatisUtil.close(sqlSession);
MyBatis输入输出参数进一步了解
假设客户端上来的数据封装成UserQueryVo,除了有User信息外,还有其他信息:
public class UserVo {
private UserPo user;
private List orderIds;
....
}
然后之前的User对象,改名成UserPo,PO表示持久对象,VO表示值对象:
package com.dane.mybatis.bean;
public class UserPo {
private int id;
private String name;
private String password;
private String account;
....
}
然后看下MyBatis这种情况参数怎么处理,这里我使用注解的方式:
public interface IUserDao3 {
@Select("select account from User where name=#{user.name}")
public List selectUsers(UserVo userVo);
}
别忘了配置Mapper:
然后测试下:
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
IUserDao3 userDao = sqlSession.getMapper(IUserDao3.class);
UserVo userVo = new UserVo();
UserPo user1 = new UserPo();
user1.setName("dane");
userVo.setUser(user1);
List users = userDao.selectUsers(userVo);
for (User user : users) {
System.out.println(user.getAccount());
}
MyBatisUtil.close(sqlSession);
接下来是Map的方式,通过HashMap封装请求信息
@Select("select id,account from User where name=#{name}
and password=#{password}")
public List selectUsersByHashMap(HashMap hashMap);
测试下:
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
IUserDao3 userDao = sqlSession.getMapper(IUserDao3.class);
HashMap map = new HashMap();
map.put("name","dane");
map.put("password","123456");
List users = userDao.selectUsersByHashMap(map);
for (User user : users) {
System.out.println(user.getAccount());
}
MyBatisUtil.close(sqlSession);
MyBatis表名与实体属性不一样的映射方法
假设数据库表Message字段为_id、_content,我们的实体类属性为id、content
SQL语句解决
@Select("SELECT _id id,_content content from Message where _id=#{id}")
public Message findMessageById(int id);
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
IUserDao3 userDao = sqlSession.getMapper(IUserDao3.class);
Message message = userDao.findMessageById(1);
System.out.println(message.getContent());
MyBatisUtil.close(sqlSession);
配置映射解决
@Select("SELECT _id ,_username,_psw,_sex FROM muser WHERE _id=#{id}")
@Results({
@Result(column="_id", property="id", id=true),
@Result(column="_username", property="username"),
@Result(column="_psw", property="psw"),
@Result(column="_sex", property="sex")})
public UserPo findUserById(int id);
非注解的方式:
MyBatis一对一表查询
根据User的name,找出User和对应的Home
public class User {
private int id;
private String name;
private String password;
private String mobile;
private int home_id;
private Home home;
.....
}
方法一:分开查询
@Select("select * from User where name = #{name}")
@Results(@Result(property = "home",column = "home_id",
one = @One(select = "com.dane.mybatis.dao.IUserDao4.getHome"
)))
User getUser(String name);
@Select("select * from Home where id = #{id}")
Home getHome(int id);
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
IUserDao4 userDao = sqlSession.getMapper(IUserDao4.class);
User user = userDao.getUser("Dane");
System.out.println(user);
MyBatisUtil.close(sqlSession);
非注解方式:
方法二:联合查询
首先写好resultMap,并在mybatis-config中配置:
@Select("select u.*, h.* from User u,Home h where u.name = #{name} and h.hid = u.home_id")
@ResultMap("rst1")
User getUser(String name);
MyBatis一对多表查询
根据hid查询出Home以及Home下所有User
分开查询
@Select("select * from Home where hid = #{id}")
@Results({
@Result(property = "id",column = "hid",id = true),
@Result(property = "name",column = "hname"),
@Result(
property = "users",column = "hid",
many = @Many(select = "com.dane.mybatis.dao.IUserDao4.getUsers"
))})
Home getHome(int id);
@Select("select * from user where home_id = #{home_id}")
List getUsers(int home_id);
非注解方式只需要把association换成collection
联合查询
注意除了association换成collection,javaType换成ofType
@Select("select h.*,u.* from Home h ,User u where hid = #{id} and h.hid = u.home_id")
@ResultMap("rst1")
Home getHome(int id);
MyBatis延迟加载
所谓的延迟加载,就是用到才去查询,比如:一对多查询,先查出了Home,home里面的users还没用到,MyBatis不会先去查询,等到我们用到getUsers时,MyBatis才去查询。
......
MyBatis配置参数路径或别名
MyBatis动态Sql
where
注解方式
@Select("")
User getUser(User user);
set
UPDATE User
name=#{name},
password=#{password},
id=#{id}
注解方式
@Select("")
User updateUser(User user);
foreach
MyBatis调用存储过程
DELIMITER $
CREATE PROCEDURE dane.student_count(IN sex INT, OUT count INT)
BEGIN
IF sex=0 THEN
SELECT COUNT(*) FROM dane.User WHERE User.sex='女' INTO count; ELSE
SELECT COUNT(*) FROM dane.student WHERE User.ssex='男' INTO count; END IF;
END
$
MyBatis缓存
MyBatis提供了一级和二级两种缓存,当进行增删改时,一级二级缓存都会被清空。
一级缓存基于PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Session flush或close之后,该session中所有cache就将清空,一级缓存默认开启。
二级缓存也是基于PerpetualCache的HashMap本地缓存,不过其存储作用域是Mapper,二级缓存默认不开启。要开启二级缓存,只需要在Mapper.xml中配置cache:
自定义缓存
实现MyBatis的Cache接口(具体自己实现),然后配置即可:
MyBaits配置package
之前我们每写一个Mapper,都需要在MyBatis-config中去配置,可以采用package进行全局配置:
如果报找不到mapper,在pom.xml下配置:
src/main/java
**/*.xml
MyBatis自动生成插件
MyBatis的org.mybatis.generator插件可以自动生成Mapper和Model代码:
添加依赖被配置resource:
org.mybatis.generator
mybatis‐generator‐maven‐plugin
1.3.2
true
true
src/main/resources
**/*.properties
在resource下新建generatorConfig.xml:
然后添加Configuration,commod line 为mybatis‐generator:generate ‐e
然后跑一下,就自动生成代码了: