- crud即增删改查 r是检索的意思,对应select
- 增、删、改操作需要提交事务!不写的话不会真正提交到数据库
idea中会显示你执行成功了,但是到系统的mysql命令行里查询数据,会发现没有执行成功,数据没有变化
mybatis中的自动序列化
mybatis接收sql或者传递参数到sql中时,可以直接保存为实体类或者传递一个实体类。mybatis可以自动根据实体类对象的属性进行序列化或者反序列化,然后与sql进行字段映射
- 映射方式为字段名映射
-
更多反序列化方式
多个同类型数据时可以采用list进行接收,对于bean可以自动接收为实体对象,map。甚至可以接收为
List<Map<,>>
一个基本类或基本类型参数使用
#
可以不需要@Param
,名称也可以不对应。如果使用了@Param,则名称必须对应- 如果使用$,则必须@Param,自然参数名称得对应
- map直接
#{键}
,不能使用@Param
。$不清楚 - bean时如果使用#。如果
$/#{bean.属性}
必须使用@Param
,参数为要对应的对象名称。如果$/#{bean.属性}
则不能使用@Param
- 注意$时引号问题
- 多个基本类或基本类型必须
@Param
@Param
对应xml**parameterType属性**
- 在接口方法中,参数直接传递Map;
User selectUserByNP2(Map<String,Object> map);
- 编写sql标签的时候,需要设置参数类型属性,参数类型为map.
- 在java中拼接出模糊查询子句然后传入sql ```java selectlike(); //模糊查询方法
TestString aa = “%smi%”;
list
<a name="ndKGM"></a>
## 关联查询
1. 方法1是直接写连接查询sql
1. 2则是通过mybatis的关联功能查
<a name="AKsB8"></a>
# Insert Update Delete
- **这三种操作需要提交事务才会事务才会被数据库保存操作结果**
- **增删改返回值即成功操作的数量**
java
int addUser(User user);//添加一个用户
int updateUser(User user);
int deleteUser(int id);
```java
<insert id="addUser" parameterType="com.kuang.pojo.User">//不需要返回类型属性
insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="com.kuang.pojo.User">
update user set name=#{name},pwd=#{pwd} where id = #{id}
</update>
java
User user = new User(5,"王五","zxcvbn");//创建一个User存储sql语句的参数,需要创建一个构造方法
int i = mapper.addUser(user); //
System.out.println(i);//这个i没什么意义,应该是告诉你执行一次addUser,可以把方法改为void
session.commit(); //提交事务
session.close();
}
-----------------------------
@Test
User user = mapper.selectUserById(1);//选择要修改的数据,虽然是查询,但是不输出查询结果
user.setPwd("asdfgh");//通过set方法修改User对象属性值
int i = mapper.updateUser(user);//执行修改,把所有user属性重新传递一遍
System.out.println(i);
session.commit(); //提交事务,重点!不写的话不会提交到数据库
session.close();
}
--------------------------------------
int i = mapper.deleteUser(5);//删除id为5的数据
System.out.println(i);
session.commit(); //提交事务,重点!不写的话不会提交到数据库
session.close();
}
## 主键
- 主键配置一般是insert
时需要配置,因为主键是唯一且非空的,传入错误的主键或者未传入主键时均容易出错,报的错一般是参数类型不匹配
,不唯一
等等 ,虽然实际上跟参数类型没关系
- useGeneratedKeys="true/false"
表示是否为自增主键,非自增时必须传入一个唯一主键值,自增时可以不传入,自动生成
- keyProperty=""
参数为实体类中作为主键的属性
- keyColumn=""
参数为数据库中的主键字段
- 还可以使用selectKey
标签完成 ,selectKey
更加灵活,支持一定程度的自定义
java
xml:
<insert id="insertSelective" parameterType="com.xxx.dataobject.UserDo" keyColumn="id"" keyProperty="id" useGeneratedKeys="true"></insert>
注解:
@Insert("INSERT INTO user(name,age) VALUES(#{user.name},#{user.age})")
@Options(useGeneratedKeys=true, keyProperty="id", keyColumn="id")
public int insertOne(@Param("user")User user);
xml
<insert id="insertUser" parameterType="User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID() //查询最后一次插入时的id
</selectKey>
insert into tb_player (id, playName, playNo,team, height)
values (
#{id,jdbcType=INTEGER},
#{playName,jdbcType=VARCHAR},
#{playNo,jdbcType=INTEGER},
#{team,jdbcType=VARCHAR},
#{height,jdbcType=DECIMAL}
)
</insert>
# 批量操作
- 批量操作时最好使用事务管理以保证多条语句的原子性
- 批量操作的本质就是一次性执行多条sql,避免多次访问数据库。
- 批量更新时需要在数据库连接配置处添加&allowMultiQueries=true
。作用是允许sql里有分号;有的教程说还要加&rewriteBatchedStatements=true
设置,作用是允许批量执行
- mybatis中批量操作有3种方法:
1. java循环调用sql
1. 使用mybatis的foreach
1. 使用mybatis提供的批处理执行器**BatchExecutor**
- 速度:c>b>a b在循环数据量很大时可能会使得sql大小超过了MySQL服务器中max_allowed_packet变量的值时,会导致操作失败,抛出PacketTooBigException
异常。
## Executor
- MyBatis 有三种基本的 Executor 执行器,SimpleExecutor
、 ReuseExecutor
、 BatchExecutor
- 执行器的生命周期只存在于当前**SqlSession**
- SimpleExecutor
:每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。(这是默认的执行器)
- ReuseExecutor可重用执行器
:执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map**BatchExecutor批处理执行器**
执行 update(没有 select,JDBC 批处理不支持 select),将所有 sql 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。(本质还是JDBC的批处理)
java
@Autowired
private SqlSessionTemplate sqlSessionTemplate;
List<User> list=...;
SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory();
//指定使用哪种执行器,而不是使用默认的执行器
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
//获取Mapper对象
UserMapper userMapper = sqlSession.getMapper(Usermapper.class);
Integer size = list.size();
try {
for (int i = 0; i < size; i++) {
User user = list.get(i);
userMapper.insertUser(user);
if (i % 1000 == 0 || i == size - 1) {
sqlSession.commit();
sqlSession.clearCache();
}
}
}catch (Throwable throwable){
sqlSession.rollback(); //抛出异常回滚
throwable.printStackTrace();
}finally {
sqlSession.close();
}
# 动态sql(xml版)
ActivitiesMapper.xml
- if
-
choose
(when, otherwise)
- when子句有一个成立就退出,不执行剩下地when。如果when都不成立,就执行otherwise。类似switch-case-break-default
- where有返回值时就会插入where,此外,如果标签返回的内容是以and 或or 开头的,则它会剔除掉。
- trim
(where
, set
)
- foreach
,循环对象集合貌似必须是map
,所以对于list必须存入map中传到foreach中
- open:条件的开始
- close:条件的结束
- separator
每一次循环的连接
- sql
,include:提取公用的sql片段,使用include引入
- 最好基于 单表来定义 sql 片段,提高片段的可重用性
- 在 sql 片段中不要包括 where
```xml
select from blog where 1=1 //根据标题与作者名查找
and title = #{title}
```xml
<!--set有返回值时会添加逗号,如果是最后一个=则不添加逗号 -->
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id};
</update>
```xml
```xml
<sql id="if-title-author"> //id为sql的标识,include通过refid和id绑定sql
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog
<where>
<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="if-title-author"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</where>
</select>
```xml
HashMap map = new HashMap();
List
```xml
<insert id="insertBatch">
INSERT INTO tb_student (name, age, phone, address, class_id) VALUES
<foreach collection="list" separator="," item="item">
(#{item.name},#{item.age},#{item.phone},#{item.address},#{item.classId})
</foreach>
</insert>
int insertBatch(List<Student>)
更多MyBatis和Mapper配置选项
MyBatis生命周期与作用域
延迟加载
- 这里只是提一下,就是使用mybatis多表连接时,不是一次性把所有关联表数据都查出来,而是先查出主表,副表的数据后面再去查询,防止每次不一定需要附表数据而过多消耗时间