面试题参考:https://blog.csdn.net/qq_33036061/article/details/105209254
| #{} | ${} |
|---|---|
| 不能写到字符串中的,如果写到字符串表达字串内容一部分。Mybatis是无法给这个占位符赋值。 | 是可以写到字符串中的,表达取中表描述的字段的值。 |
| 使用jdbc的预编译处理,可以有防止sql注入。 | 取字符的值,有sql注入的可能。 |
1 | resultType:主要针对于从数据库中提取相应的数据出来 |
- namespace
namespace中的包名要和接口的包名一致!

- select
id:就是对应的namespace中的方法名;
resultType:Sql语句执行的返回值!
parameterType:参数类型
一、XML使用
XML(不使用注解操作数据库,推荐使用map),核心配置文件必须按顺序添加,不然会报错
xml配置文件
1 |
|
- 编写接口
1 | public interface UserDao { |
编写对应的mapper中的sql语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<mapper namespace="dao.UserDao">
<!-- select查询语句 -->
<select id="getUserList" resultType="pojo.User">
select * from test.user
</select>
<select id="getUserById" resultType="pojo.User" parameterType="int">
select * from test.user where id=#{id}
</select>
<!-- 对象中的属性,User中的属性,可以直接取出来 -->
<insert id="addUser" parameterType="pojo.User">
insert into test.user values(#{id},#{name},#{pwd})
</insert>
<update id="updateUser" parameterType="pojo.User">
update test.user set id = #{id}, pwd=#{pwd} where name=#{name}
</update>
<delete id="deleteUser" parameterType="int">
delete from test.user where id=#{id}
</delete>
</mapper>测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public void getUserList() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
public void getUserById() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.getUserById(1);
System.out.println(user);
sqlSession.close();
}
//需要提交事务,才可以将数据插入到数据库中
// sqlSession.commit();
public void addUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
int temp = userDao.addUser(new User(4,"凯","123456"));
if(temp>0) {
System.out.println("成功");
//需要提交事务,才可以将数据插入到数据库中
sqlSession.commit();
}
sqlSession.close();
}
public void upadateUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
int temp = userDao.updateUser(new User(4,"凯","123123"));
if(temp>0) {
System.out.println("成功");
//需要提交事务,才可以将数据插入到数据库中
sqlSession.commit();
}
sqlSession.close();
}
public void deleteUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
int temp = userDao.deleteUser(4);
if(temp>0) {
System.out.println("成功");
//需要提交事务,才可以将数据插入到数据库中
sqlSession.commit();
}
sqlSession.close();
}利用mybatis进行模糊插叙时,要么使用如下方式要么使用 like concat(concat(‘%’,#{xxx}),’%’)

XML配置文件
引入外部配置文件
1 | <!-- 引入外部配置文件 |
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件的信息。
类型别名
- 第一种
1 | <!-- 可以给实体类起别名 --> |
- 第二种
也可以指定一个包名,扫描实体类的包名,,默认的别名就是这个类的类名,首字母小写(建议)
1 | <!-- 可以给实体类起别名 包名--> |
实体类较少时可以使用第一种,可以自定义别名
实体类多时使用第二种,不能自定义别名
- 第三种
在实体类上加上注解**@Alias(“XXX”)**也可以实现
以下的别名为hello

其它的数据类型的默认别名


结果集映射
如果实体类中的属性与数据库中的字段不对应,可以使用结果集映射
1 | <select id="getUserById" resultMap="UserMap"> |
日志log4j
1 | <!-- 日志 --> |
二、注解使用
在工具类创建的时候实现自动提交事务
1 | public static SqlSession getSqlSession() { |
编写接口,添加注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public interface UserDao {
List<User> getUsers();
// 当参数为基本数据类型或String类型时,所有的参数前必须加上@Param("xxx")注解
//引用类型不需要写@Param("xxx")注解
User getUserById( int id);
void addUser(User user);
void upadateUser( int id, String name);
void deleteUser( int id);
}测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61public class AppTest {
//查询全部数据
public void getUserList() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> user = userDao.getUsers();
for (User user2 : user) {
System.out.println(user2);
}
sqlSession.close();
}
//根据ID查询
public void getUserById() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.getUserById(1);
System.out.println(user);
sqlSession.close();
}
//插入数据
public void addUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
userDao.addUser(new User(4,"袁","123123"));
sqlSession.close();
}
//修改数据
public void updateUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
userDao.upadateUser(4, "凯");
sqlSession.close();
}
//删除数据
public void deleteUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
userDao.deleteUser(4);
sqlSession.close();
}
}【注意:必须要将接口注册绑定到我们的核心配置文件中】

@Param()注解
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加
- 如果一只有一个基本类型的话,可以忽略,但是建议加上
- SQL中的引用就是@Param()中设定的属性名
按照查询嵌套处理(多张表有关系时)
子查询、联表查询时





对象:associatio 【多对一】
集合:collection【一对多】
javaType=”x” 指定实体类中属性的类型
ofType 之低昂映射到List或者集合中的pojo类型,泛型中的约束类型。
集合中的泛型信息,使用ofType获取


当java中实体类的属性名与数据库中的字段名不一致时(数据库中存在”_”)
mapUnderscoreToCamelCase
是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。
数据库中的的名字为test_Test时java中可以使用 testTest

UUID
生成唯一的32位的随机数,在数据库中设定id时可以使用,以便形成唯一的用户
1 | System.out.println(UUID.randomUUID().toString().replaceAll("-", "")); |
动态SQL语句
在SQL中增加逻辑代码
在select中使用if条件进行查询时,方便进行判断查询操作,动态查询数据库中的信息。
例如以下例子,当传递过来的属性不为空时,则在其sql语句中增加sql语句

上面这种方式where后面需要加上1=1,不好
where
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
1 | <select id="queryData" parameterType="map" resultType="user"> |
choose
使用choose时,则只能执行一条语句,都都不符合when的条件则执行otherwise
1 | <where> |
Set
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列,元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
1 | <!-- 动态sql 更新 --> |
SQL片段
将一些功能相同部分抽取出来,方便复用
使用SQL标签抽取公共的部分
1
2
3
4
5
6
7
8<sql id="sql-name-pwd">
<if test="name != null">
name = #{name}
</if>
<if test="pwd != null">
and pwd = #{pwd}
</if>
</sql>在需要使用的地方使用include标签引入
1
2
3
4
5
6<select id="queryData" parameterType="map" resultType="user">
select * from user
<where>
<include refid="sql-name-pwd"></include>
</where>
</select>
注意:
- 最好是单表查询来定义SQL片段,多表效率会低,
- 抽取的SQL片段中不要有where标签
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)

1 | <select id="queryData" parameterType="map" resultType="user"> |
1 | Map<String,Object> map = new HashMap<String, Object>(); |
一级缓存(默认开启)
一级缓存也叫本地缓存,SqlSession
与数据库相同操作期间查询到的数据会放在本地缓存中。
以后如果需要获取相同的数据,直接从缓存中拿,不必再去操作数据库。
一级缓存只在如下部分有效。

缓存失效的情况:
- 查询不同的东西 。
- 增删改查操作,可能会改变原来的数据,所以必定会刷新缓存。
- 查询不同的Mapper.xml。
- 手动清理缓存 使用 sqlSession.clearCache(); //手动清理缓存。
总结:一级缓存是默认开启的,只在一次SqlSession中有效,也就是拿到这个连接到关闭这个连接区间中 。
二级缓存
开启全局缓存
cacheEnabled:全局性地开启或关闭所有映射器配置文件中已配置的任何缓存
1
2
3
4
5
6
7
8
9<!-- 设置 -->
<settings>
<!-- 日志 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 运行java使用驼峰属性名匹配数据库中的带"_"的字段名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 显示开启全局缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>在xml文件中使用二级缓存
<cache/>需要将实体类序列化,否则报错:Caused by: java.io.NoSerializableException:com.ykq
解决:在实体类中实现接口Serializable

也可以使用如下,可自定义
1
2
3
4
5<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
缓存顺序:
二级缓存》一级缓存》查询数据库