5 单表
值参数(如 id=1):用 #{ }(安全,防注入)。
表名 / 字段名 / sql语句(SQL 语法部分):用 ${ }(直接拼接,不加单引号)。
在MyBatis中的.xml中写sql语句时,只要为表定义了别名,就从头到尾都使用这个别名来引用它的字段。因为,MyBatis 对表名直接访问字段和通过别名访问字段的大小写、解析逻辑存在差异,用别名能避免因系统(如 MySQL 在不同环境下的大小写处理、MyBatis 自身解析规则)对表名、字段名的误处理,确保 SQL 中字段引用稳定且符合预期,从而避免 “未知列” 等因命名解析引发的错误。
注:下面给的代码是两个项目里的,两个项目里的user类字段不一样,主要看写法。
5.1 查询
5.1.1 普通查询
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.lsl.dao.UserDao">
<!-- id:方法名称 -->
<!-- resultType:数据返回的类型 -->
<select id="findAll" resultType="com.lsl.entity.User">
select * from user;
</select>
<!--
通过id查询
SQL语句使用#{占位符的名称,名称可以任意},仅限于基本数据类型和String类型
-->
<select id="findById" resultType="com.lsl.entity.User" parameterType="java.lang.Integer">
select * from user where id = #{id}
</select>
<select id="findByName" resultType="com.lsl.entity.User" parameterType="java.lang.String">
select * from user where username = #{username}
</select>
<!-- 多个参数可以直接使用user对象 -->
<select id="findByUser1" resultType="com.lsl.entity.User" parameterType="com.lsl.entity.User">
select * from user where username = #{username} and password = #{password}
</select>
<!-- 分页查询 -->
<select id="findAllUser" parameterType="java.lang.Integer" resultType="com.lsl.entity.User">
select * from user limit #{param1} offset #{param2}
</select>
<select id="findAllUserByUsername" parameterType="com.lsl.entity.User" resultType="com.lsl.entity.User">
select * from user where username = #{username} limit #{pageSize} offset #{pageStart}
</select>
<!-- 具体函数的查询 -->
<select id="findByCount" resultType="int">
select count(*) from user
</select>
</mapper>
UserDao
package com.lsl.dao;
import com.lsl.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserDao {
public abstract List<User> findAll();
User findById(Integer id);
List<User> findByName(String username);
List<User> findByUser1(User user);
List<User> findAllUser(Integer pagesize,Integer pageStart);
List<User> findAllUserByUsername(User user);
public Integer findByCount();
}
对于实体类User,最好实现Serializable这个接口,如果用到MyBatis的二级缓存,就必须要实现这个接口。
public class UserTest {
private InputStream in = null;
private SqlSession session = null;
private UserDao userDao = null;
@Before //前置通知, 在方法执行之前执行
public void init() throws IOException {
//加载主配置文件,目的是为了构建SqlSessionFactory对象
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//通过SqlSessionFactory工厂对象创建SqlSesssion对象
session = factory.openSession();
//通过Session创建UserDao接口代理对象
userDao = session.getMapper(UserDao.class);
}
@After //@After: 后置通知, 在方法执行之后执行 。
public void destory() throws IOException {
//释放资源
if (session != null) { // 增加null检查
session.close();
}
in.close();
}
@Test
public void aaa(){
List<User> users = userDao.findAll();
for (User user: users
) {
System.out.println(user.toString());
}
}
@Test
public void findByName(){
List<User> users = userDao.findByName("熊大");
for(User user:users){
System.out.println(user.toString());
}
}
@Test
public void findByUser1(){
User user = new User();
user.setUsername("熊大");
user.setPassword("123");
List<User> users = userDao.findByUser1(user);
for(User user1:users){
System.out.println(user1.toString());
}
}
@Test
public void findAllUser(){
Integer pageSize = 5;
Integer pageIndex = 1;
Integer pageStart = pageSize * (pageIndex-1);
List<User> users = userDao.findAllUser(pageSize,pageStart);
for(User user1:users){
System.out.println(user1.toString());
}
}
@Test
public void findAllUserByUsername(){
User user = new User();
user.setUsername("小李");
user.setPageSize(5);
user.setPageStart(0);
List<User> users = userDao.findAllUserByUsername(user);
for(User user1:users){
System.out.println(user1.toString());
}
}
@Test
public void testFindByCount() throws Exception {
Integer count = userDao.findByCount();
System.out.println("总记录数:"+count);
}
}
5.1.2 模糊查询
<!-- 模糊查询 -->
<select id="findByName" resultType="com.qcby.domain.User" parameterType="string">
<!-- 第一种方式的SQL语句-->
select * from user where username like #{username}
</select>
<select id="findByName1" resultType="com.qcby.domain.User" parameterType="string">
<!-- 第二种SQL语句的编写 强调:'%${value}%'不能修改,固定写法(不推荐使用) -->
select * from user where username like '%${value}%'
</select>
public List<User> findByName(String username);
public List<User> findByName1(String username);
// 第一种
@Test
public void testFindByName() throws Exception {
List<User> list = mapper.findByName("%王%");
for (User user : list) {
System.out.println(user);
}
}
// 第二种
@Test
public void testFindByName1() throws Exception {
List<User> list = mapper.findByName1("王");
for (User user : list) {
System.out.println(user);
}
}
- 使用#{}时:需在参数中包含通配符%,例如where name like #{name},传入的参数应为"%张三%"
- 使用${}时:可在 SQL 中直接拼接通配符,例如where name like '%${value}%',传入的参数为"张三"
- 值参数(如 id=1):用 #{ }(安全,防注入)。
- 表名 / 字段名 / sql语句(SQL 语法部分):用 ${ }(直接拼接,不加单引号)。
5.1.3 动态sql
<select id="findByWhere" parameterType="com.qcby.domain.User" resultType="com.qcby.domain.User">
select * from user where 1 = 1
<if test="username != null and username != ''">
and username like #{username}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</select>
// 条件查询
public List<User> findByWhere(User user);
@Test
public void testFindByWhere(){
User user = new User();
user.setUsername("%熊%");
user.setSex("女");
List<User> users = mapper.findByWhere(user);
System.out.println(users);
}
- 智能处理 SQL 中的 WHERE 关键字,自动剔除标签内拼接 SQL 开头的多余 AND/OR,避免语法错误;
- where标签目的就是为了去掉 where 1=1的拼接的。
- where标签使用在if标签的外面。
<!-- 动态sql-->
<!-- where if 传入了那些参数就查那些-->
<select id="findUser" resultType="com.lsl.entity.User" parameterType="com.lsl.entity.User">
select * from user
<where>
<if test="username!=null and username!=''">
username = #{username}
</if>
<if test="birthday!=null">
and birthday=#{birthday}
</if>
<if test="address!=null and address!=''">
and address = #{address}
</if>
<if test="password!=null and password!=''">
and password = #{password}
</if>
</where>
</select>
<!--使用where关键字-->
<select id="findByWhere1" parameterType="com.qcby.domain.User" resultType="com.qcby.domain.User">
select * from user
<where>
<if test="username != null and username != ''">
and username like #{username}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</where>
</select>
List<User> findUser(User user);
public List<User> findByWhere1(User user);
@Test
public void findUser(){
User user = new User();
user.setUsername("熊大");
user.setAddress("上海");
user.setPassword("123");
List<User> users = userDao.findUser(user);
for(User user1:users){
System.out.println(user1.toString());
}
}
@Test
public void testFindByWhere1(){
User user = new User();
user.setSex("女");
List<User> users = mapper.findByWhere1(user);
System.out.println(users);
}
3.<choose>+<when>+<otherwise>
多条件分支判断(类似 Java 的 if-else if-else),仅执行第一个满足条件的 <when> 片段,都不满足则执行 <otherwise>;
<!-- 相当于if else-if else -->
<select id="selectUserByChoose" resultType="com.lsl.entity.User" parameterType="com.lsl.entity.User">
select * from user
<where>
<choose>
<when test="username!=null and username!=''">
username = #{username}
</when>
<when test="birthday!=null">
and birthday=#{birthday},
</when>
<otherwise>
and id=#{id}
</otherwise>
</choose>
</where>
</select>
4.<trim>
自定义 SQL 片段的前后缀处理,通过 prefix(前缀)、suffix(后缀)、prefixOverrides(剔除前缀多余内容)、suffixOverrides(剔除后缀多余内容)灵活控制拼接;
<select id="selectUserByUsernameAndSex" parameterType="com.lsl.entity.User"
resultType="com.lsl.entity.User">
select * from user
<trim prefix="where" prefixOverrides="and | or">
<if test="username!=null and username!=''">
username = #{username}
</if>
<if test="birthday != null">
and birthday = #{birthday}
</if>
<if test="address != null and address!=''">
and address = #{address}
</if>
<if test="password !=null and password!=''">
and password = #{password}
</if>
</trim>
</select>
@Test
public void selectUserByUsernameAndSex(){
User user = new User();
user.setUsername("熊大");
// user.setAddress("上海");
user.setPassword("123");
List<User> users = userDao.selectUserByUsernameAndSex(user);
for (User user1: users) {
System.out.println(user1.toString());
}
}
5.<foreach>
遍历集合(如 List、Array 等),常用于批量操作(如 IN 条件、批量插入 / 删除),可指定遍历的元素分隔符、索引、元素变量名等;
<!-- collection:当前要循环的数组或者集合 -->
<!-- item: 我们指定要循环的数组的每一个元素 -->
<!-- separator:每一个元素应该用什么来做分割 -->
<!-- open:当前循环是以什么开始 -->
<!-- close:当前循环是以什么结束 -->
<!--foreach标签 select * from user where id = 1 or id = 2 or id = 3 -->
<select id="findByIds" parameterType="com.qcby.domain.User" resultType="com.qcby.domain.User">
select * from user
<where>
<foreach collection="ids" open="id = " separator="or id = " item="i">
#{i}
</foreach>
</where>
</select>
<!--foreach标签 select * from user where id in (1,2,3)-->
<select id="findByIds1" parameterType="com.qcby.domain.User" resultType="com.qcby.domain.User">
select * from user
<where>
<!--这个ids是user类里面的字段,private List<Integer> ids;-->
<foreach collection="ids" open="id in ( " separator="," close=")" item="i">
#{i}
</foreach>
</where>
</select>
@Test
public void testFindByIds(){
User user = new User();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
user.setIds(ids);
List<User> list = mapper.findByIds(user);
System.out.println(list);
}
@Test
public void testFindByIds1(){
User user = new User();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
user.setIds(ids);
List<User> list = mapper.findByIds1(user);
System.out.println(list);
}
6.<sql>+<include>
SQL 片段复用,将通用 SQL 片段(如字段列表、条件)用 <sql> 定义,再通过 <include> 引入,减少重复代码。
<!--提取公共的SQL-->
<sql id="findAllSql">
select * from user
</sql>
<!--编写sql语句(重点练习的) com.qcbyjy.mapper.UserMapper.findAll -->
<select id="findAll2" resultType="com.qcby.domain.User">
<include refid="findAllSql" />
/*select * from user*/
</select>
<!--使用where关键字-->
<select id="findByWhere2" parameterType="com.qcby.domain.User" resultType="com.qcby.domain.User">
<include refid="findAllSql" />
/*select * from user*/
<where>
<if test="username != null and username != ''">
and username like #{username}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</where>
</select>
<!--foreach标签 select * from user where id in (1,2,3)-->
<select id="findByIds2" parameterType="com.qcby.domain.User" resultType="com.qcby.domain.User">
<include refid="findAllSql" />
/*select * from user*/
<where>
<foreach collection="ids" open="id in ( " separator="," close=")" item="i">
#{i}
</foreach>
</where>
</select>
@Test
public void testFindAll2(){
List<User> users = mapper.findAll2();
System.out.println(users);
}
@Test
public void testFindByWhere2(){
User user = new User();
user.setSex("女");
List<User> users = mapper.findByWhere2(user);
System.out.println(users);
}
@Test
public void testFindByIds2(){
User user = new User();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
user.setIds(ids);
List<User> list = mapper.findByIds2(user);
System.out.println(list);
}
5.2 修改
5.2.1 普通修改
<!-- 修改 -->
<update id="update" parameterType="com.qcby.domain.User">
update user set username = #{username},birthday = #{birthday},sex = #{sex},address=#{address} where id = #{id}
</update>
public void update(User user);
@Test
public void testUpdate() throws Exception {
User user = mapper.findById(5);
user.setUsername("小凤");
mapper.update(user);
session.commit();
}
5.2.2 动态sql
- 主要用于 SELECT(拼接查询条件),虽理论可用于复杂 DELETE,但并非 DELETE 操作的常规用法;
- 系列主要用于 SELECT 的多分支条件筛选,在增、删、改中极少用到;
- 虽可用于批量查、增、删,但单条增 / 删 / 查中基本用不到。
- 、、+是通用标签(所有 CRUD 操作均可能用到)
<update id="update" parameterType="com.lsl.entity.User">
update user
<set>
<if test="username!=null and username!=''">
username = #{username},
</if>
<if test="birthday!=null">
birthday=#{birthday},
</if>
<if test="address!=null and address!=''">
address = #{address},
</if>
<if test="password!=null and password!=''">
password = #{password},
</if>
</set>
where id=#{id}
</update>
int update(User user);
@Test
public void update(){
User user = new User();
user.setUsername("sssssss");
user.setId(1);
userDao.update(user);
session.commit();
}
2.<trim>
<update id="trimUpdate" parameterType="com.lsl.entity.User">
update user
<trim prefix="set" suffixOverrides=",">
<if test="username!=null and username!=''">
username = #{username},
</if>
<if test="birthday != null">
birthday = #{birthday},
</if>
<if test="address != null and address!=''">
address = #{address},
</if>
<if test="password !=null and password!=''">
password = #{password},
</if>
</trim>
where id = #{id}
</update>
@Test
public void trimUpdate(){
User user = new User();
user.setUsername("老王");
user.setId(1);
userDao.trimUpdate(user);
session.commit();
}
5.3 新增
5.3.1 普通新增
<insert id="insert" parameterType="com.lsl.entity.User">
insert into user (username ,birthday,sex,address,password) value(#{username},#{birthday},#{sex},#{address},#{password})
</insert>
<!-- 返回主键,我们主键需要设置为自动递增 注册 -->
<insert id="insert1" parameterType="com.qcby.domain.User">
/*
<selectKey> 是 MyBatis 中用于获取插入操作后自动生成的主键值的标签
keyProperty表示要返回的属性名称,是直接将查询到的主键值赋值给这个传入的 User 对象的 id 属性。
order取值AFTER表示插入数据后的行为
resultType表示返回值的类型,此处为 Integer,与 User 的 id 类型匹配
*/
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id();
</selectKey>
insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
</insert>
标签通过 keyProperty="id" 指定的 “id”,是直接将查询到的主键值赋值给这个传入的 User 对象的 id 属性。
执行完成后,你无需额外获取新对象,直接通过原来的 user.getId() 就能拿到自动生成的主键值。
Integer insert(User user);
public void insert1(User user);
@Test
public void insert(){
User user = new User();
user.setSex("女");
user.setAddress("保定");
user.setUsername("sss");
userDao.insert(user);
session.commit();
}
@Test
public void testInsert() throws Exception {
User user = new User();
user.setUsername("美美");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("顺义");
mapper.insert(user);
session.commit();
System.out.println(user.getId());
}
5.3.2 动态sql
1.<foreach>
<!-- collection:当前要循环的数组或者集合 -->
<!-- item: 我们指定要循环的数组的每一个元素 -->
<!-- separator:每一个元素应该用什么来做分割 -->
<!-- open:当前循环是以什么开始 -->
<!-- close:当前循环是以什么结束 -->
<!--insert into 表名 (字段) values (值),(值)-->
<insert id="insertMoreByList" >
insert into user(username,birthday,sex,address) values
<foreach collection="users" item="user" separator=",">
(#{user.username},#{user.birthday},#{user.sex},#{user.address})
</foreach>
</insert>
//@Param的核心作用是给参数指定名称,方便在 XML 中通过${名称}或#{名称}引用
int insertMoreByList(@Param("users") List<User> users);
@Test
public void insertMoreByList(){
User user1 = new User("小赵",new Date(),"男","保定");
User user2 = new User("小张",new Date(),"男","保定");
User user3 = new User("小李",new Date(),"男","保定");
List<User> users = Arrays.asList(user1,user2,user3);
userDao.insertMoreByList(users);
session.commit();
}
- 不写parameterType完全可以传参,MyBatis 会自动推断类型;
- @Param是显式指定参数名的方式,更清晰且避免歧义,上面代码中不写也可以
- 使用时只需导入org.apache.ibatis.annotations.Param即可,前提是项目已引入 MyBatis 依赖。
5.4 删除
5.4.1 普通删除
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>
@Test
public void delete(){
userDao.delete(5);
session.commit();//事务提交
}
5.4.2 动态sql
1.<foreach>
<!-- collection:当前要循环的数组或者集合 -->
<!-- item: 我们指定要循环的数组的每一个元素 -->
<!-- separator:每一个元素应该用什么来做分割 -->
<!-- open:当前循环是以什么开始 -->
<!-- close:当前循环是以什么结束 -->
<!--delete from user where id in (1,2,3,4,5); -->
<delete id="deleteMoreByArray">
delete from user where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
int deleteMoreByArray(@Param("ids") Integer[] ids);//强制入参
@Test
public void deleteMoreByArray(){
Integer[] integer = new Integer[]{6,7,8};
userDao.deleteMoreByArray(integer);
session.commit();
}

6651

被折叠的 条评论
为什么被折叠?



