Mybatis映射文件的sql编写合集(由简入难)

本文详细介绍了MyBatis中实体类的创建、配置文件的编写,包括多对一和一对多关系的处理,以及动态SQL语句的使用。通过示例展示了全查、按条件查询、一对多查询和动态where语句的实现,并提供了测试代码和执行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 首先创建一个java项目,配置好jar包

一、所需配置文件的编写

1.实体类

先来解释一下多对一和一对多

多对一:多个员工属于一个部门,每一个员工都有一个部门属性,所以在员工类中加入一个部门对象属性

一对多:一个部门拥有多个员工,多个员工就可以是一个数组/集合(我选择集合,方便操作),那就是在部门类中加入一个员工集合对象

字段说明

        部门:dept类

                id        主键自增        int

                dept_no        部门编号        int        唯一索引

                dept_name        部门名称        varchar

                     user类

                 id        主键自增        int

                user_name        员工姓名        varchar        默认索引

                password        员工密码        varchar

                age        员工年龄        int

                dept_no        部门编号        int

随便插入几条数据:

dept:

user:

下面是实体类:

1.Dept类

package ssm.domain;

import java.util.List;

/**
 * @TableName dept
 */
public class Dept{
    private Integer id;
    private Integer dept_no;
    private String dept_name;
    //一对多的体现
    private List<User> users;

    public Dept() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getDept_no() {
        return dept_no;
    }

    public void setDept_no(Integer dept_no) {
        this.dept_no = dept_no;
    }

    public String getDept_name() {
        return dept_name;
    }

    public void setDept_name(String dept_name) {
        this.dept_name = dept_name;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    @Override
    public String toString() {
        String s= ", users=" + users;
        String str = users == null?"":users.get(0).getUserName()==null?"":s;
        return "Dept{" +
                "id=" + id +
                ", dept_no=" + dept_no +
                ", dept_name='" + dept_name + '\'' +
                str +
                '}' + "\n";
    }
}

 2.User类

package ssm.domain;

/**
 * 
 * @TableName user
 */
public class User {

    private Integer id;
    private String userName;
    private String password;
    private Integer age;
    private String deptNo;
    //多对一
    private Dept dept;

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getDeptNo() {
        return deptNo;
    }

    public void setDeptNo(String deptNo) {
        this.deptNo = deptNo;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        String s = ", dept=" + dept;
        String str = dept == null?"":dept.getDept_name()==null ? "":s;
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", deptNo='" + deptNo + '\'' +
                str +
                '}' + "\n";
    }
}

2.jdbc.properties

username=root
password=数据库密码
url=jdbc:mysql://localhost:3306/数据库名?characterEncoding=utf-8&serverTimezone=UTC
#下面是8.0的数据库的driver,5.x的把cj去掉
driver=com.mysql.cj.jdbc.Driver

3.sqlMapConfig.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>
    <!--引入jdbc数据库信息,即jdbc配置信息-->
    <properties resource="jdbc.properties"/>
    <!--设置是否启用驼峰命名,就是数据库的字段如果是x_a,那么xA就是它-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--给实体类起别名:包名.类名-->
    <typeAliases>
        <typeAlias type="ssm.domain.Dept" alias="dept"/>
    </typeAliases>
    <!--配置数据库信息,${这里写的是jdbc.properties里等号左边去掉"jdbc."的内容}-->
    <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>
    <!--注册mapper,每一个mapper类都需要注册才能被识别使用-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
        <mapper resource="DeptMapper.xml"/>
    </mappers>
</configuration>

4.全查

 实体类和配置文件都已经写好了,下面开始编写接口,实现方式有两种,一种是注解的方式,一种是配置文件的方式。我们从最简单的语句开始,比如全查

我们在DeptMapper接口和UserMapper接口中都写一个全查的方法:

//这是注解的方式,注解是非常简单的开发方式,省去了配置文件里复杂的标签
@Select("select * from dept")
List<Dept> selectAll();

虽然注解的方式非常简单,但是复杂的查询语句(如多表联查)用配置文件会更加简单,接下来展示DeptMapper.xml文件里的内容

<!--首先是文件头-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--接着是mapper标签对,namespace属性是用来指定mapper接口文件的-->
<mapper namespace="ssm.mapper.DeptMapper">
    <!--我们实体类中添加了不属于dept表中字段的属性,就需要配置属性与表中字段一一对应
        id是自己起的名字,type是对应的实体类的全路径,如果在sqlMapConfig.xml文件中配置了类别名,则直接使用类名即可
    -->
    <resultMap id="BaseResultMap" type="ssm.domain.Dept">
        <!--
            id标签:对应的是主键
            result标签:对应的是普通的字段
            property属性:对应的是实体类中的属性名
            column属性:对应的是数据库中的字段名
            jdbcType:数据库中字段的数据类型,其实不需要写
        -->
        <id property="id" column="id" jdbcType="INTEGER"/>
        <result property="dept_no" column="dept_no" jdbcType="VARCHAR"/>
        <result property="dept_name" column="dept_name" jdbcType="VARCHAR"/>
        <!--dept实体类中有一个user类的集合对象,所以还要配置它(有两种方式,下面这个是最常用的方式),集合的标签是collection
            property:实体类中的属性名
            javaType:实体类中属性的类型,这里就是List
            ofType:list集合中存放的是什么类型的数据,这里就是user
        -->
        <collection property="users" javaType="java.util.List" ofType="ssm.domain.User">
            <result property="id" column="id"/>
            <result property="userName" column="user_name"/>
            <result property="password" column="password"/>
            <result property="age" column="age"/>
            <result property="deptNo" column="dept_no"/>
        </collection>
        <!--还有第二种方式,比上面的简略一些-->
        <!--
            column:是select属性所指向的查询语句所需要的参数
            因为是根据部门id查询员工,那么传入的dept_no就是dept类中的dept_no
        -->
        <!--<collection property="users" column="dept_no"
                    javaType="java.util.List" ofType="ssm.domain.User" select="指向mapper接口的全路径.方法名,如果是在本配置文件中编写的,那就直接写方法名,下面贴一个在本配置文件下写的代码图,这里就不做演示了"/>-->
    </resultMap>
    <!--现在操作的表只有零星几个字段,如果字段多了那么每一条查询语句都写会非常麻烦,这里有一个sql标签,用于存储数据库中的字段名,id是自己起的名字,见名知意-->
    <sql id="Base_Column_List">
        id,dept_no,dept_name
    </sql>
    <!--下面是全查功能的实现,有些人可能会想我写*也行,可以但不建议,因为全查dept返回的结果里没有list集合,那返回的结果类型可以直接用实体类-->
    <select id="selectAll" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from dept
    </select>

到这里我们已经写好了部门类的实体类,接口,配置文件里实现了一个全查的功能,我们简单测试一下(采用单元测试的方式测试)

public class UserTest {
    //因为sqlSession是可以公共使用的,@Befor就是在每一个单元测试启动的时候都加载,将每次要用的公共方法放在这里,提高代码复用性
    static SqlSession sqlSession;

    @Before
    public void setUp() throws IOException {
        //获取sqlmap-config配置文件
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获取工厂
        SqlSessionFactoryBuilder bu = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = bu.build(in);
        //创建session
        sqlSession = factory.openSession();
    }

    //对Dept的全查
    @Test
    public void selectAllForDept() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> z = mapper.selectAllByUserName("张");
        System.out.println(z);
    }
    //和@Before相对的就是after,适合放关闭资源等代码
    @After
    public void tearDown() {
        sqlSession.commit();
        sqlSession.close();
    }

内部方法的截图:

 程序运行的截图:

5.一个参数的查询(非id)

对于员工类的全查就不做详细介绍了,大家自己写一写吧

下面演示根据一个参数查询(以dept_no演示吧,正好一会要用到,写在UserMapper接口中,返回的是List集合)

下面是接口:

List<User> selectByDeptNo(@Param("deptNo") String deptNo);

下面是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="ssm.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="ssm.domain.User">
        <id property="id" column="id" jdbcType="INTEGER"/>
        <result property="userName" column="user_name" jdbcType="VARCHAR"/>
        <result property="password" column="password" jdbcType="VARCHAR"/>
        <result property="age" column="age" jdbcType="INTEGER"/>
        <result property="deptNo" column="dept_no" jdbcType="VARCHAR"/>
        <!--这里演示select的方式,findOneByDeptNo方法在DeptMapper接口中,并在DeptMapper.xml里实现方法,这个一定要有,不然就注释掉,否则运行会报错,单个对象用association-->
        <association property="dept" javaType="ssm.domain.Dept" select="ssm.mapper.DeptMapper.findAllByDept_no" column="dept_no"/>
    </resultMap>

    <sql id="Base_Column_List">
        id,user_name,password,
        age,dept_no
    </sql>

    <select id="selectByDeptNo" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from user
        where
        dept_no = #{deptNo,jdbcType=VARCHAR}
    </select>
</mapper>

简单测试一下(dept为null是正常的,因为我并没有去查dept的内容)

    @Test
    public void selectByDeptNo(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.selectByDeptNo(1001);
        System.out.println(users);
    }

6.多对一查询

上文解释的一对多,还有上一步在UserMapper.xml里的配置返回结果集,其实已经实现多对一,还是上面的代码,把association这一行放出来,把它select所指向的方法实现,如下:

//DeptMapper.java
    List<Dept> findAllByDept_no(@Param("dept_no") Integer dept_no);
<!--DeptMapper.xml-->
    <select id="findAllByDept_no" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from dept
        where
        dept_no = #{dept_no,jdbcType=NUMERIC}
    </select>

 现在再去运行刚才的测试方法,就可以得到一个多对一的结果啦

 一开始看到多对一和一对多真的觉得好绕啊,这么一写是不是觉得简单很多

7.一对多查询

 理清思绪,一对多就等于查询一个部门的所有员工,那么这个查询语句当然要写在部门接口中啦

//一对多的体现,既然是一,那返回的就是一个部门对象
    Dept findByDept_name(@Param("dept_name") String dept_name);

上文我们在dept中是将user对象的字段拿出来一个一个做了对照,那我们这边就要用到外连接查询,不知不自觉的竟然将多表联查也讲到了,记得在sql标签中将id和dept_no前加上"表名.",因为user表中也有id和dept_no,需要告诉数据库我查的是谁的id和dept_no

//Deptmapper.java
    //一对多的体现,既然是一,那返回的就是一个部门对象
    Dept findByDept_name(@Param("dept_no") Integer dept_no);
<!--DeptMapper.xml-->
    <select id="findByDept_name" resultMap="BaseResultMap" parameterType="integer">
        select
        <include refid="Base_Column_List"/>,u.*
        from dept left join user u on dept.dept_no = u.dept_no
        where
        dept.dept_no = #{dept_no,jdbcType=VARCHAR}
    </select>

测试一下

    //一对多的体现
    @Test
    public void selectMoreToOne(){
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept b = mapper.findByDept_name(1001);
        System.out.println(b);
    }

8.动态sql语句

1.where-if

先写好接口中的方法,在user接口中下如下方法

 //where--它是条件查询,用id查询就没意思了,加入模糊查询那么返回的就可能是一个集合
    List<User> findOneByUserNameAndDeptNo(@Param("userName") String userName, @Param("deptNo") Integer deptNo);

先看普通的where写法,可以看到需要一个恒为true的表达式作为where和条件的衔接,否则会出现where and 这样的情况

       select id="findOneByUserNameAndDeptNo" resultType="domain.User">
        select
        <include refid="Base_Column_List"/>
        from user
        where 1=1
            <if test="userName!=null and userName!=''">
                AND user_name like concat('%',#{userName,jdbcType=VARCHAR},'%')
            </if>
            <if test="deptNo!=null and deptNo!=''">
                AND dept_no = #{deptNo,jdbcType=VARCHAR}
            </if>
    </select>

 再看<where></where>标签对,标签对直接对and/or做了处理,注意哦,它只处理字符串开头的and/or

select id="findOneByUserNameAndDeptNo" resultType="domain.User">
        select
        <include refid="Base_Column_List"/>
        from user
        <where>
            <if test="userName!=null and userName!=''">
                AND user_name like concat('%',#{userName,jdbcType=VARCHAR},'%')
            </if>
            <if test="deptNo!=null and deptNo!=''">
                AND dept_no = #{deptNo,jdbcType=VARCHAR}
            </if>
        </where>
    </select>

这边只有if单支判断,如果是多支捏,那就用到了choose--when--otherwise,等同于java的switch--case--default

select id="findOneByUserNameAndDeptNo" resultType="domain.User">
        select
        <include refid="Base_Column_List"/>
        from user
        <where>
            <choose>
                <when test="userName!=null and userName!=''">
                    user_name like concat('%',#{userName,jdbcType=VARCHAR},'%')
                </when>
                <when test="deptNo!=null and deptNo!=''">
                    dept_no = #{deptNo,jdbcType=VARCHAR}
                </when>
                <otherwise>
                    1=1
                </otherwise>
            </choose>
        </where>
    </select>

 我这边因为功能都是相同的,所以结果都是一样的,下面是测试类中的代码

 //where
    @Test
    public void whereTest(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> oneByUserNameAndDeptNo = mapper.findOneByUserNameAndDeptNo("张", null);
        System.out.println("oneByUserNameAndDeptNo = " + JSON.toJSONString(oneByUserNameAndDeptNo));
    }

 下面是结果图和执行的sql语句

2.where-in-foreach

大家肯定在都见到过一些网页上/软件上的批量删除,sql中用的就是where in()子查询,下面是mybatis中的写法,首先附上接口中的方法

    //参数可以传数组,集合和可变长度参数列表
    int deleteById(@Param("ids") Integer... ids);

然后来看xml里的代码

 <delete id="deleteById">
        delete
        from user
        where id in
        /*
        collection:方法里param里是啥这里是啥
        item:取此次循环所对应的值
        open:以什么开始
        close:以什么结束
        separator:以什么分割
        */
        <foreach collection="ids" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </delete>

 foreach还是很简单的,下面是测试类的代码(增删改都需要提交事务,sqlsession.commit()),我的数据库里有id为5,6,7的数据,那我们就删除5,6,7

    //批量删除
    @Test
    public void DeletesTest() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.deleteById(5, 6, 7);
        System.out.println("成功删除" + i + "条");
    }

可以看到结果删除成功了三条数据

3.set

我们看到set那就应该想到更新数据吧,毕竟它们两个是搭档啊,set+if实现传入参数字段的修改,首先附上接口中的方法

    int updateUser(User user);
 <update id="updateUser">
        update user
        <set>
            <if test="userName!=null and userName!=''">
                user_name = #{userName,jdbcType=NUMERIC}
            </if>
            <if test="password!=null and password!=''">
                password = #{password,jdbcType=NUMERIC}
            </if>
            <if test="age!=null and age!=''">
                age = #{age,jdbcType=NUMERIC}
            </if>
            <if test="deptNo!=null and deptNo!=''">
                deptNo = #{deptNo,jdbcType=NUMERIC}
            </if>
        </set>
        where id = #{id}
    </update>

常用的动态语句所用标签大致就这么些,如有新发现,另做补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尢词

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值