一、 前言
一切当以官方文档为基准。
参考视频狂神说Java-Mybatis
本文之前的操作步骤:Mybatis入门-第一个程序
前置内容:
- Java
- maven
- MySQL
- JDBC
- JavaWeb中持久化层的一些知识,如POJO
环境:
- Java11
- IDEA 2019.3.3
- MySQL8
- mybatis3
路径:
代码
UserMapper:
package com.duzhuan.dao;
import com.duzhuan.pojo.User;
import java.util.List;
/**
* @Autord: HuangDekai
* @Date: 2020/9/9 19:42
* @Version: 1.0
* @since: jdk11
*/
public interface UserMapper {
List<User> getUserList();
}
UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.duzhuan.dao.UserMapper">
<resultMap id="UserMap" type="com.duzhuan.pojo.User">
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserList" resultMap="UserMap">
select * from mybatis.user
</select>
</mapper>
User:
package com.duzhuan.pojo;
/**
* @Autord: HuangDekai
* @Date: 2020/9/9 14:11
* @Version: 1.0
* @since: jdk11
*/
public class User {
private int id;
private String name;
private String password;
public User() {
}
public User(int id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
/*getter and setter*/
/*toString*/
}
MybatisUtils:
package com.duzhuan.utils;
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 java.io.IOException;
import java.io.InputStream;
/**
* @Autord: HuangDekai
* @Date: 2020/9/9 21:38
* @Version: 1.0
* @since: jdk11
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
二、增删改查
1.通过id查询用户
Usermapper:
package com.duzhuan.dao;
import com.duzhuan.pojo.User;
import java.util.List;
/**
* @Autord: HuangDekai
* @Date: 2020/9/9 19:42
* @Version: 1.0
* @since: jdk11
*/
public interface UserMapper {
List<User> getUserList();
//------------ 新增的语句 --------------------
User getUserById(int id);
//------------------------------------------
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.duzhuan.dao.UserMapper">
<resultMap id="UserMap" type="com.duzhuan.pojo.User">
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserList" resultMap="UserMap">
select * from mybatis.user
</select>
<!--================新增的语句=================-->
<select id="getUserById" parameterType="int" resultMap="UserMap">
select * from mybatis.user where id = #{id}
</select>
<!--=========================================-->
</mapper>
paramterType中写的是getUserById这个方法的参数的数据类型,但是深究下去的话可以知道,在这里并不区分大小写,而且涉及到别名,这里暂时只用知道这里的int
其实对应的是Integer
。具体可看Mybatis3-设置-类型别名中的类型别名(typeAliases)。同时,parameterType只能填入一个数据类型,因此,对应的Mapper中的方法显然只能有一个输入参数。
#{id}
,#{}
是取参数的一种方式,id即在Mapper中传入的参数的名字。
Mybatis里有#{}
和${}
两种取值方式 ,前者类似于JDBC中的PrepareStatement,而${}
则更像是字符串拼接,会导致SQL注入。
在UserMapperTest里添加的测试样例:
@Test
public void getUserByIdTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
2.模糊查询
在UserMapper添加:
List<User> getUserListByName(String name);
在UserMapper.xml的根标签里添加:
<select id="getUserListByName" parameterType="String" resultMap="UserMap">
select * from mybatis.user where name like concat('%',#{name},'%')
</select>
concat可以较为方便地实现模糊查询
测试样例:
@Test
public void getUserListByNameTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserListByName("a");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
结果:
3.分页查询
分页查询的目的就是为了减少数据的处理量。
在UserMapper
中添加方法:
List<User> getUserListLimit(Map<String,Integer> map);
在UserMapper.xml
的根标签中添加:
<select id="getUserListLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
在UserMapperTest
中添加测试样例:
@Test
public void getUserListLimitTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Integer> map = new HashMap<>();
map.put("startIndex",0);
map.put("pageSize",3);
List<User> userListLimit = mapper.getUserListLimit(map);
for (User user : userListLimit) {
System.out.println(user);
}
sqlSession.close();
}
输出结果:
这里可以看出使用Map作为参数的方便之处,因为从理论上讲,一个Map就可以解决所有的输入参数。但是Map对于维护来讲实在是个灾难,因此,在有条件的情况下,尽量使用实体类作为输入参数吧。
4.增删改
在Mybatis中,若mybatis-config.xml中配置的transactionManager标签的type是JDBC,那么事务自动提交默认是关闭的。
如果要增删改,就要使用sqlSession.commit()方法提交修改才能持久化。
4.1 增
UserMapper中增加:
int addUser(User user);
insert语句会返回一个int值表示改变的行数,因此该方法设置了返回值数据类型为int。
UserMapper.xml的根标签里增加:
<insert id="addUser" parameterType="com.duzhuan.pojo.User">
insert into mybatis.user(`id`,`name`,`pwd`) value (#{id},#{name},#{password})
</insert>
这里使用的不再是<select>
标签,而是insert
。但是id
依旧是UserMapper
里对应的方法的的方法名。可以看到,UserMapper中该方法传入的参数是一个实体类,不是基本类型,我们也没有对其设置别名,因此parameterType
输入的应该是该实体类的全限定名称。
仔细观察可以发现,SQL语句里用的并非是User.getId,而是直接使用了实体类里属性的属性名。
测试样例:
@Test
public void addUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(6, "Gala", "123456");
int updateLine = mapper.addUser(user);
if (updateLine>0){
System.out.println("Add user ------>"+user);
sqlSession.commit();
}
else{
System.out.println("Failed");
}
sqlSession.close();
}
结果:
4.2 删
UserMapper中添加方法:
int delUserById(int id);
UserMapper.xml的根标签里添加:
<delete id="delUserById" parameterType="int">
delete from mybatis.user where id = #{id};
</delete>
与增加基本一致,只是换成了<delete>
标签。
测试样例:
@Test
public void delUserByIdTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
int id = 6;
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userById = mapper.getUserById(id);
int updateLine = mapper.delUserById(id);
if (updateLine>0){
System.out.println("Del user -------->"+userById);
sqlSession.commit();
}
else{
System.out.println("Failed");
}
sqlSession.close();
}
4.3 改
UserMapper中添加方法:
int updateUser(User user);
UserMapper.xml的根标签里添加:
<update id="updateUser" parameterType="com.duzhuan.pojo.User">
update mybatis.user set `name` = #{name}, `pwd` = #{password} where `id` = #{id}
</update>
与增、删的操作基本一致,只是使用<update>
标签。
测试样例:
@Test
public void updateUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(5, "bin", "123456");
User oldUser = mapper.getUserById(user.getId());
int updateLine = mapper.updateUser(user);
if (updateLine > 0){
System.out.println("Update User from:");
System.out.println(oldUser);
System.out.println("to");
System.out.println(user);
sqlSession.commit();
}
else{
System.out.println("Failed");
}
sqlSession.close();
}
结果:
三、配置
1.properties
这是之前写的配置文件(mybatis-config.xml):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="qq123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.duzhuan.dao.UserMapper"></mapper>
</mappers>
</configuration>
property的属性可以在外部配置,并可以进行动态替换,有利于解耦。
例如将连接数据库的配置放到外部:
db.properties代码:
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC
username = root
password = qq123456
mybatis-config.xml代码修改为:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--=====================add=========================-->
<properties resource="db.properties"></properties>
<!--==============================================-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--================update=================-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<!--=================================-->
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.duzhuan.dao.UserMapper"></mapper>
</mappers>
</configuration>
部分环境中可能出现xml中有中文注释不能运行的问题。注意顺序,在XML里标签前后顺序不能改变,即<properties>
必须在<environments>
前。
由于是Maven项目,因此properties
中resource
的值可以直接写文件名。另外,根据官方文档也可以给出这样的例子:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="user"/>
<property name="password" value="qq123456"/>
</properties>
甚至也可以在 SqlSessionFactoryBuilder.build() 方法中传入属性值。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
// ... 或者 ...
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);
官方文档给出了优先级:
如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:
- 首先读取在 properties 元素体内指定的属性。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。
建议尽量只使用一种方式。
再次运行测试样例,运行通过就没问题了。
这里运行了getUserListTest()获取结果:
可以正常运行。
2.别名
下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
别名 映射的类型 _byte byte _long long _short short _int int _integer int _double double _float float _boolean boolean string String byte Byte long Long short Short int Integer integer Integer double Double float Float boolean Boolean date Date decimal BigDecimal bigdecimal BigDecimal object Object map Map hashmap HashMap list List arraylist ArrayList collection Collection iterator Iterator
上面是Mybatis默认有的类型别名。建立自己的类型别名可以使用注解(不利于维护,不推荐),这里不介绍。下面是使用XML配置类型别名,将com.duzhuan.pojo.User
别名设置为User
使用:
修改mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"></properties>
<!--=====================add======================-->
<typeAliases>
<typeAlias type="com.duzhuan.pojo.User" alias="User"></typeAlias>
</typeAliases>
<!--==============================================-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.duzhuan.dao.UserMapper"></mapper>
</mappers>
</configuration>
那么,在这个配置文件中注册的Mapper(这里即com.duzhuan.dao.UserMapper)可以将User
作为com.duzhuan.pojo.User
使用。
修改UserMapper中带有com.duzhuan.pojo.User
的项为User
:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.duzhuan.dao.UserMapper">
<resultMap id="UserMap" type="User">
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserList" resultMap="UserMap">
select * from mybatis.user
</select>
<select id="getUserById" parameterType="int" resultMap="UserMap">
select * from mybatis.user where id = #{id}
</select>
<select id="getUserListByName" parameterType="String" resultMap="UserMap">
select * from mybatis.user where name like concat('%',#{name},'%')
</select>
<insert id="addUser" parameterType="User">
insert into mybatis.user(`id`,`name`,`pwd`) value (#{id},#{name},#{password})
</insert>
<delete id="delUserById" parameterType="int">
delete from mybatis.user where id = #{id};
</delete>
<update id="updateUser" parameterType="User">
update mybatis.user set `name` = #{name}, `pwd` = #{password} where `id` = #{id}
</update>
</mapper>
这里再次用getUserListTest
去测试:
结果一致。
官方文档中还有使用<package>
的,类似于下面:
<typeAliases>
<package name="com.duzhuan.pojo"/>
</typeAliases>
这样就能直接把包内的所有类的类名作为别名。但是这样的话别名就只能是类名,而<typeAliase>
可以用alias
属性命名别的名字。
3.映射器
映射器,即mappers。
我们在上面将UserMapper绑定的操作使用的是使用映射器接口实现类的完全限定名:
<mappers>
<mapper class="com.duzhuan.dao.UserMapper"></mapper>
</mappers>
这种方式要求:
- Mapper与其对应的Mapper.xml同名
- Mapper于其对应的Mapper.xml在同一目录
其余方法观看官方文档即可,对于下面这种方式不推荐使用:
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>