Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
1、 mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息。
2、 mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
3、 通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
4、 SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
5、 Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括HashMap集合对象、POJO对象类型。
mybatis-3.5.0/lib下所有包
mybatis-3.5.0.jar
mysql-connector-java-5.1.37-bin.jar
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=/home/miracle/Desktop/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
User
package com.miracle.model;
import java.util.Date;
public class User {
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
public User() {
}
public User(String username, String sex, Date birthday, String address) {
this.username = username;
this.sex = sex;
this.birthday = birthday;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
", address='" + address + '\'' +
'}';
}
}
select last_insert_id()
insert into user (username, sex, birthday, address)
value
(#{username}, #{sex}, #{birthday}, #{address})
delete from user where id = #{id}
update user set address = #{address}, sex = #{sex}
where id = #{id}
package com.miracle.test;
import com.miracle.orm.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.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
/**
* 普通方式
*/
public class Demo {
private SqlSession sqlSession;
/**
* 获取session
* @throws IOException
*/
@Before
public void init() throws IOException {
// 1.读取配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession();
}
/**
* 提交事务
*/
@After
public void destory(){
sqlSession.commit();
sqlSession.close();
}
/**
* 查询
*/
@Test
public void test1(){
// 这里写xml映射文件的 namespace + id
User user = (User) sqlSession.selectOne("com.miracle.orm.User.findUserById", 10);
System.out.println(user);
List userList = sqlSession.selectList("com.miracle.orm.User.findUserByName", "张");
System.out.println(userList);
}
/**
* 插入
*/
@Test
public void test2(){
User user = new User("gyf2", "1", new Date(), "广州");
// 返回受影响的行数
int affectRow = sqlSession.insert("com.miracle.orm.User.insertUser", user);
System.out.println(affectRow);
}
/**
* 删除
*/
@Test
public void test3(){
// 返回受影响的行数
int affectRow = sqlSession.delete("com.miracle.orm.User.deleteUser", 33);
System.out.println(affectRow);
}
/**
* 更新
*/
@Test
public void test4(){
User user = new User();
user.setId(27);
user.setSex("男");
user.setAddress("深圳");
// 返回受影响的行数
int affectRow = sqlSession.update("com.miracle.orm.User.updateUser", user);
System.out.println(affectRow);
}
/**
* 插入后获取插入数据的id,设置到JavaBean中
*/
@Test
public void test5(){
User user = new User("gyf3", "2", new Date(), "广州");
// 返回受影响的行数
int affectRow = sqlSession.insert("com.miracle.orm.User.insertUser", user);
System.out.println(affectRow);
// 返回插入数据的id
int id = user.getId();
System.out.println(id);
}
}
Mapper代理的开发方式,程序员只需要编写mapper接口(相当于dao接口)即可。Mybatis会自动的为mapper接口生成动态代理实现类。
不过要实现mapper代理的开发方式,需要遵循一些开发规范。
1. mapper接口的全限定名要和mapper映射文件的namespace的值相同。
2. mapper接口的方法名称要和mapper映射文件中的statement的id相同;
3. mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
4. mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致;
编写mapper接口:UserMapper
package com.miracle.mapper;
import com.miracle.model.User;
import com.miracle.vo.UserQueryVo;
import java.util.List;
import java.util.Map;
public interface UserMapper {
/*
有时候去数据库查询一条记录多个列,
这是没有对应业务的JavaBean对象,
可以把单条查询结果封装到map中,
以列名为key,列值为value
*/
public Map getEmpByIdReturnMap(Integer id);
/**
* @param user
* @return 受影响的行数
*/
// 使用mapper方式开发,那么接口方法的参数只能接收一个参数
public int save(User user);
public User findUserById(int id);
public List findUserByUserQueryVo(UserQueryVo userQueryVo);
public List findUserListByMap(Map map);
public int findUserCount(UserQueryVo userQueryVo);
public User findUserByIdResultMap(int id);
public List findUserList(UserQueryVo userQueryVo);
public List findUserByIds(UserQueryVo userQueryVo);
public List findUserByIds2(List ids);
/*
mybatis 增删改 在接口放回方法处
允许将返回值 void 改为:
Integer:表示影响行数
Long:表示影响行数
Boolean:影响行数超过一,返回true,否则false
*/
public Long addEmp(Employee employee);
public Long updateEmp(Employee employee);
public Boolean deleteEmpById(Integer id);
}
编写xml映射文件:UserMapper.xml
insert into user (username, sex, birthday, address)
value (#{username}, #{sex}, #{birthday}, #{address})
sex = #{user.sex}
and username like '%${user.username}%'
insert into tbl_employee(last_name, email, gender) values (
#{lastName},#{email},#{gender}
)
update tbl_employee
set last_name = #{lastName},
email = #{email},
gender = #{gender}
where id = #{id}
delete from tbl_employee where id = #{id}
编写测试
package com.miracle.test;
import com.miracle.mapper.UserMapper;
import com.miracle.model.User;
import com.miracle.vo.UserQueryVo;
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.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
/**
* mapper代理方式,mapper就相当于dao,用mapper开发就不需要dao了,service层直接调用mapper
*/
@SuppressWarnings("all")
public class Demo {
private SqlSession sqlSession;
private UserMapper userMapper;
/**
* 获取session
* @throws IOException
*/
@Before
public void init() throws IOException {
// 1.读取配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession();
// 获取mapper
userMapper = sqlSession.getMapper(UserMapper.class);
}
/**
* 提交事务
*/
@After
public void destory(){
sqlSession.commit();
sqlSession.close();
}
/**
* 查询
*/
@Test
public void test1(){
// 查询
User user = userMapper.findUserById(1);
System.out.println(user);
}
/**
* 保存
*/
@Test
public void test2(){
// 保存
User user = new User("王五", "x", new Date(), "xx");
userMapper.save(user);
}
/**
* 复杂类型查询
*/
@Test
public void test3(){
User user = new User();
user.setId(1);
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setUser(user);
List userList = userMapper.findUserByUserQueryVo(userQueryVo);
System.out.println(userList);
}
/**
* map类型查询
*/
@Test
public void test4(){
Map map = new HashMap<>();
map.put("user", "张");
map.put("sex", 1);
List userList = userMapper.findUserListByMap(map);
System.out.println(userList);
}
@Test
public void test5(){
UserQueryVo userQueryVo = new UserQueryVo();
User user = new User();
user.setSex("2");
userQueryVo.setUser(user);
int count = userMapper.findUserCount(userQueryVo);
System.out.println(count);
}
@Test
public void test6(){
User user = userMapper.findUserByIdResultMap(1);
System.out.println(user);
}
@Test
public void test7(){
User user = new User();
user.setUsername("张");
user.setSex("1");
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setUser(user);
List userList = userMapper.findUserList(userQueryVo);
System.out.println(userList);
}
/**
* foreach 遍历JavaBean中的list
*/
@Test
public void test8(){
List ids = new ArrayList<>();
ids.add(10);
ids.add(16);
ids.add(22);
ids.add(24);
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setIds(ids);
List userList = userMapper.findUserByIds(userQueryVo);
System.out.println(userList);
}
/**
* foreach 遍历list
*/
@Test
public void test9(){
List ids = new ArrayList<>();
ids.add(10);
ids.add(16);
ids.add(22);
ids.add(24);
List userList = userMapper.findUserByIds2(ids);
System.out.println(userList);
}
}
properties
settings
typeAliases
typeHandlers
objectFactory
objectWrapperFactory
plugins
environments?
databaseIdProvider
mappers
mybatis可以使用properties来引入外部properties配置文件的内容
1.#{} 和 ${} 区别
#{}:相当于预处理中的占位符?。(底层是JDBC的preparedstatement)
#{}里面的参数表示接收java输入参数的名称。
#{}可以接受HashMap、POJO类型的参数。
当接受简单类型的参数时,#{}里面可以是value,也可以是其他。
#{}可以防止SQL注入。
使用场景:
尽量用#{}取值
${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。(底层是JDBC的statement)
${}会引起SQL注入,所以要谨慎使用。
${}可以接受HashMap、POJO类型的参数。
当接受简单类型的参数时,${}里面只能是value。
使用场景:
比如分表,排序... 按照年份分表拆分:
select * from ${year}_salary whrere xxx
select * from tbl_employee order by ${f_name} ${asc}
If标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上。
注意:用if进行判断是否为空时,不仅要判断null,也要判断空字符串‘’;
eg:见下图
会去掉条件中的第一个and符号。
eg:见下图
需求:
想根据JavaBean更新数据库记录,当JavaBean字段非空则更新响应字段,空则不更新
update tbl_employee
set
last_name = #{lastName},
email = #{email},
gender = #{gender}
where id = #{id}
但是这个sql执行会有问题,if标签里面的sql后面有个逗号,无法处理,这是要用到set标签
update tbl_employee
last_name = #{lastName},
email = #{email},
gender = #{gender}
where id = #{id}
insert into tbl_dept
dept_id,
dept_name,
#{deptId,jdbcType=INTEGER},
#{deptName,jdbcType=VARCHAR},
Mybatis提供了SQL片段的功能,可以提高SQL的可重用性。
2.selectOne和selectList
selectOne:只能查询0或1条记录,大于1条记录的话,会报错:
selectList:可以查询0或N条记录
3.mybatis特殊字符处理
使用符号进行说明,在最里层的[ ]里面内容不进行解析
4.输出映射 resultType/resultMap
(1)resultType
使用resultType进行结果映射时,查询的列名和映射的pojo属性名完全一致,该列才能映射成功。
如果查询的列名和映射的pojo属性名全部不一致,则不会创建pojo对象;
如果查询的列名和映射的pojo属性名有一个一致,就会创建pojo对象。
输出单个pojo对象和pojo列表时,mapper映射文件中的resultType的类型是一样的,mapper接口的方法返回值不同。同样的mapper映射文件,返回单个对象和对象列表时,mapper接口在生成动态代理的时候,会根据返回值的类型,决定调用selectOne方法还是selectList方法。
(2)resultMap(当mybatis返回JavaBean嵌套JavaBean时,向内层JavaBean里面设置值可以用resultMap)
如果查询出来的列名和属性名不一致,通过定义一个resultMap将列名和pojo属性名之间作一个映射关系。
1、 定义resultMap
2、使用resultMap作为statement的输出映射类型
(3)总结
resultType:将查询结果按照sql列名pojo属性名一致性映射到pojo中。
resultMap:使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:将关联查询信息映射到一个pojo对象中。
collection:将关联查询信息映射到一个list集合中。
5.mybatis标签大全
https://blog.csdn.net/weixin_40950778/article/details/78655288