MyBatis从环境搭建到精通增删改查

写本篇博客主要是因为我刚刚学完前端Vue技术,再回看后端内容的时候发现已经忘得差不多了,故以此篇巩固知识、也方便大家复习。

一、搭建maybatis环境

第一步:创建maven工程,然后一直点下一步就可以了

 

第二步:引入pom依赖

    <dependencies>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

第三步:创建mybatis核心文件

<?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>
    <!--
        mybatis核心配置文件中的标签必须按照指定的顺序进行配置:
        properties typeAliases environments mappers
    -->
    <properties resource="jdbc.properties"/>
    <typeAliases>
        <!--
            type:设置需要起别名的类型
            alias:设置某个类型的别名
        -->
        <!--
                <typeAlias type="" alias=""></typeAlias>
            如果不设置alias,当前类型拥有默认的别名,即类名,且不区分大小写
        -->
        <!--
            通过包来设置别名,指定包下所有类型将全部拥有默认的别名,且为类名
        -->
        <package name="pojo"></package>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入mybatis的映射文件-->
    <mappers>
        <!--
        <mappers resource="mappers/UserMapper.xml"/>
    -->
        <!--
        以包的方式引入映射文件,但是必须满足两个条件:
        1.mapper接口和映射文件所在的包必须一致
        2.mapper接口的名字和映射文件的名字必须一致
    -->
        <package name="mapper"></package>
    </mappers>
</configuration>

第四步:配置连接数据库的核心文件并连接数据库

注意url中/db1是我自己的数据库,大家记得修改为你要连接的数据库

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db1?serverTimezone=UTC
jdbc.username=root
jdbc.password=root

创建数据库的时候,只需要点击+号--->数据源--->mysql即可

 点击进来以后,需要手动填写的是用户、密码、数据库三个部分,然后测试连接,连接通过后就可点击应用了

 

第五步:建表

use db1;

create table users(
    uid int not null primary key auto_increment,
    uname varchar(10) not null,
    uage int not null
);

insert into users(uname,uage) values ('张三',20),('李四',16);

接下来就是创建实体类、编写mybatis代码以及测试了

这是我创建的文件目录,大家可以照着创建

 

第六步:创建实体类

package pojo;

import lombok.*;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
    private int uid;
    private String uname;
    private int uage;

    public User(String uname,int uage){
        this.uname=uname;
        this.uage=uage;
    }
}

第七步:

编写mapper接口以及对应的xml脚本

接口:

public interface UserMapper {

    User getUserById(int id);


}

xml:注意命名空间是接口的全限定名

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.UserMapper">

    <!--查(单个用户)-->
    <select id="getUserById" parameterType="int" resultType="user">
        select uid,uname,uage
        from users
        where uid=#{uid}
    </select>

 

</mapper>

第八步:编写测试代码

import mapper.UserMapper;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import pojo.User;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class test1 {
    SqlSession sqlSession;
    @Before
    public void openSqlSession() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("MybatisConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        sqlSession=factory.openSession();
    }

    @After
    public void closeSqlSession(){
        sqlSession.close();
    }

    @Test
    public void testGetUserById(){
        UserMapper uMapper = sqlSession.getMapper(UserMapper.class);
        User user = uMapper.getUserById(2);
        System.out.println(user);
    }




}

运行截图:

 

至此,mybatis基本环境已经搭建好了。

二、基础---增删改查

2.1 增

2.1.1 单个增加

接口:

    /*单个增加*/
    void addUser(User user);

xml:

    <!--增(单个增加)-->
    <insert id="addUser" parameterType="user">
        insert into users(uname,uage) values (#{uname},#{uage})
    </insert>

测试:注意,因为jdbc提交事务的时候将autocommit设置为false,所以如果想将数据插入到数据库而不被回滚,可以手动提交事务;也可以在打开sqlSession的时候传入参数true

    @Test
    public void testAddUser(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user=new User("王五",42);
        mapper.addUser(user);
        sqlSession.commit();
    }

批注:

MyBatis事务:

openSession():默认开启事务,进行增删改操作后需要使用sqlSession.commit();手动提交事务

openSession(true):可以设置为自动提交事务(关闭事务)

2.1.2 单个增加并返回主键

接口:注意返回值是操作行成功的数量,而不是返回的主键。

    /*单个增加但返回主键*/
    void addUserReturnKey(User user);

xml:设置useGeneratedKeys="true",并用keyProperty接收返回的主键

    <!--增(单个增加但返回主键)-->
    <insert id="addUserReturnKey" parameterType="user" useGeneratedKeys="true" keyProperty="uid">
        insert into users(uname,uage) values (#{uname},#{uage})
    </insert>

测试:通过user.getUid()得到返回的主键

    @Test
    public void testAddUserReturnKey(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user=new User("柳七",24);
        mapper.addUserReturnKey(user);
        sqlSession.commit();
        System.out.println(user.getUid());
    }

2.1.3 批量添加

接口:

    /*批量增加*/
    void addUsers(List<User> users);

xml:

    <!--增(批量增加)-->
    <insert id="addUsers" parameterType="user">
        insert into users(uname,uage) values
        <foreach collection="list" item="user" separator=",">
            (#{user.uname},#{user.uage})
        </foreach>
    </insert>

测试:

    @Test
    public void testAddUsers(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = new User("李信", 34);
        User user2 = new User("芈月", 28);
        User user3 = new User("孙策", 41);
        List<User> list=new ArrayList<>();
        list.add(user1);list.add(user2);list.add(user3);
        mapper.addUsers(list);
        sqlSession.commit();
    }

批注:

标签参数详解:

collection:用来指定入参的类型

如果是List集合,则为list

如果是Map集合,则为map

如果是数组,则为array

item:每次循环遍历出来的值或对象

separator:多个值或对象或语句之间的分隔符

open:整个循环外面的前括号

close:整个循环外面的后括号

2.2 改

2.2.1 修改全部字段

接口:

    /*修改全部字段*/
    void updateAllById(User user);

xml:

    <!--改(修改全部字段)-->
    <update id="updateAllById" parameterType="user">
        update users
        set
        uname=#{uname},
        uage=#{uage}
        where uid=#{uid}
    </update>

测试:

    @Test
    public void testUpdateAllById(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateAllById(new User(4,"韩信",25));
        sqlSession.commit();
    }

2.2.2 动态修改字段

接口:

    /*动态修改字段*/
    void updateDynamically(User user);

xml:注意,if语句中只有字符串类型需要额外判空(是否为空字符串),其他类型则不需要。

但是我在建表的时候设置了uage为not null,也就是说如果不设置uage会填充默认值,所以这里判断了uage是否为0(不设置uage默认为0)

if里的修改语句每一行后加上逗号,别忘了!

    <!--改(动态修改字段)-->
    <update id="updateDynamically" parameterType="user">
        update users
        <set>
            <if test="uname != null and uname != ''">
                uname=#{uname},
            </if>
            <if test="uage != null and uage != 0">
                uage=#{uage},
            </if>
        </set>
        where uid=#{uid}
    </update>

测试:

    @Test
    public void testUpdateDynamically(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user=new User();
        user.setUid(1);
        user.setUname("张斯瑞");
        mapper.updateDynamically(user);
        sqlSession.commit();
    }

2.3 删

2.3.1 单个删除

接口:

    /*单个删除*/
    void deleteUserById(int uid);

xml:

    <!--删(单个删除)-->
    <delete id="deleteUserById" parameterType="int">
        delete from users where uid=#{uid}
    </delete>

测试:

    @Test
    public void testDeleteById(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUserById(1);
        sqlSession.commit();
    }

2.3.2 批量删除

接口:

    /*批量删除*/
    void deleteBatch(int[] uids);

xml:

    <!--删(批量删除)-->
    <delete id="deleteBatch">
        delete from users where uid in
        <foreach collection="array" item="uid" open="(" close=")" separator=",">
            #{uid}
        </foreach>
    </delete>

测试:

    @Test
        public void testDeleteBatch(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int[] uids=new int[]{2,4,5};
        //也可以用下面的语句简单的初始化数组
        //int[] test={2,4,5};
        mapper.deleteBatch(uids);
        sqlSession.commit();
    }

2.4 查

2.4.1 单个查询

接口:

    /*查询单个用户*/
    User getUserById(int id);

xml:

    <!--查(单个用户)-->
    <select id="getUserById" parameterType="int" resultType="user">
        select uid,uname,uage
        from users
        where uid=#{uid}
    </select>

测试:

    @Test
    public void testGetUserById(){
        UserMapper uMapper = sqlSession.getMapper(UserMapper.class);
        User user = uMapper.getUserById(7);
        System.out.println(user);
    }

2.4.2 批量查询

接口:

    /*动态查询用户*/
    List<User> getUserDynamically(int[] uids);

xml:

    <sql id="allColumns">
        uid,uname,uage
    </sql>
    <!--查(动态查询用户)-->
    <select id="getUserDynamically" resultType="user">
        select <include refid="allColumns"/>
        from users
        where uid in
        <foreach collection="array" item="uid" open="(" close=")" separator=",">
            #{uid}
        </foreach>
    </select>

测试:

    @Test
    public void testGetUserDynamically(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int[] uids={6,7,8};
        List<User> list = mapper.getUserDynamically(uids);
        list.forEach(System.out::println);
    }

运行截图:

批注:

动态sql:

可以定义代码片段,可以进行逻辑判断,可以进行循环处理(批量处理),使条件判断更为简单

1):用来定义代码片段,可以将所有的列名,或复杂的条件定义为代码片段,供使用时调用

2):用来引用定义的代码片段

定义的时候:

<sql id="allColumns"> uid,uname,uage </sql>

引用的时候:

<include refid="allColumns"/>

 

2.4.3 全部查询

接口:

    /*查询所有用户*/
    List<User> getAllUsers();

xml:

    <!--查(所有用户)-->
    <select id="getAllUsers" resultType="user">
        select <include refid="allColumns"/> from users;
    </select>

测试:

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

至此,基本的增删查改就结束了。

三、进阶---复杂条件处理

3.1 传入多个参数

可以通过#{arg0}~#{argX} 指定参数名称

如果入参是多个,实体类包不住,但可以通过指定参数位置进行传参。

因为实体类只能封装住成员变量的条件,如果某个成员变量要有区间范围内的判断,或者有两个值进行处理,则实体类包不住

接口:

    /*查询年龄区间*/
    List<User> getRangeAge(int startAge,int endAge);

xml:不用指定parameterType,因为它把握不住。直接使用arg0~argX

    <!--查(指定区间)-->
    <select id="getRangeAge" resultType="user">
        select <include refid="allColumns"/> from users
        where uage between #{arg0} and #{arg1}
    </select>

测试:

    @Test
    public void testGetRangeAge(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = mapper.getRangeAge(25, 35);
        list.forEach(System.out::println);
    }

运行截图:

 

3.2 入参是map

如果入参超过一个以上,使用map封装查询条件,更有语义,查询条件更加明确

接口:

    /*查询年龄区间以外的用户*/
    List<User> getNotRangeAge(Map map);

xml:

    <!--查(指定区间以外的用户)-->
    <select id="getNotRangeAge" resultType="user">
        select <include refid="allColumns"/> from users
        where uage not between #{startAge} and ${endAge}
    </select>

测试:

    @Test
    public void testGetNotRangeAge(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map map=new HashMap();
        map.put("startAge",25);
        map.put("endAge",35);
        List<User> list = mapper.getNotRangeAge(map);
        list.forEach(System.out::println);
    }

3.3 @Param指定参数名称

@Param("columnName"):这里定义的columnName的名称是要在xml文件中的${引用定义的名称}

接口:

  /*查询指定列值*/
    List<User> getByColumn(@Param("columnName")String columnName,@Param("columnValue")int columnValue);

xml:注意列名要用${}拼接,而列值无论是不是String类型,都可以用#{}拼接

    <!--查询指定列值-->
    <select id="getByColumn" resultType="user">
        select <include refid="allColumns"/> from users
        where ${columnName}=#{columnValue};
    </select>

测试:

    @Test
    public void testGetByColumn(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = mapper.getByColumn("uage", 41);
        list.forEach(System.out::println);
    }

运行截图:

    /*返回值是map(一行)*/
    Map getReturnMap(int uid);

 

3.4 返回值是map

3.4.1 一行

如果返回的数据实体类无法包含,可以使用map返回多张表中的若干数据,返回后这些数据之间没有任何关系,就是Object类型;返回的map的key就是列名或别名

接口:

    /*返回值是map(一行)*/
    Map getReturnMap(int uid);

xml:

    <!--查(返回值是单行map)-->
    <select id="getReturnMap" parameterType="int" resultType="map">
        select uname,uage
        from users
        where uid=#{uid}
    </select>

测试:

    @Test
    public void testGetReturnMap(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map map = mapper.getReturnMap(8);
        System.out.println(map);
        System.out.println(map.get("uname"));
        System.out.println(map.get("uage"));
    }

运行截图:

3.4.2 多行

接口:

    /*返回值是map(多行)*/
    List<Map> getReturnMaps();

xml:

    <!--查(返回值是多行map)-->
    <select id="getReturnMaps" resultType="map">
        select uname,uage from users
    </select>

测试:

    @Test
    public void testGetReturnMaps(){
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<Map> list = mapper.getReturnMaps();
        list.forEach(System.out::println);
    }

运行截图:

 

3.5 列名与类中成员变量名称不一致

为了说清楚具体的解决方案,另建表

create  table book(
    bookid int(11) not null primary key auto_increment,
    bookname varchar(32) not null comment '图书名称'
);

insert into book(bookid, bookname) values(1,'java基础'),(2,'sql基础');

建实体类:

package pojo;

import lombok.*;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
    private int uid;
    private String uname;
    private int uage;

    public User(String uname,int uage){
        this.uname=uname;
        this.uage=uage;
    }
}

3.5.1 解决方案一:使用别名

使用列的别名,别名与类中的成员变量名一样,即可完成注入

接口:

package mapper;

import pojo.Book;

import java.util.List;

public interface BookMapper {

    List<Book> getAllBooks();

}

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="mapper.BookMapper">
    <!--
        mapper接口和映射文件要保证两个一致:
        1.mapper接口的全类名和映射文件的namespace一致
        2.mapper接口中的方法的方法名要和映射文件中的sql的id保持一致
    -->
    <select id="getAllBooks" resultType="book">
        select bookid bookId,bookname bookName from book
    </select>

</mapper>

测试:注意在创建SqlSessionFactoryBuilder()以后调用的build()函数里传入的是mybatis的核心配置文件

import mapper.BookMapper;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import pojo.Book;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class test2 {

    SqlSession sqlSession;

    @Before
    public void openSqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = sqlSessionFactory.openSession();
    }

    @After
    public void closeSqlSession(){
        sqlSession.close();
    }

    @Test
    public void testGetAllBooks(){
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        List<Book> books = mapper.getAllBooks();
        books.forEach(System.out::println);
    }
}

运行截图:

 

3.5.2 解决方案二:使用resultMap

使用标签进行映射,只需要修改xml文件即可

注意主键用id标签,非主键用result标签

    <resultMap id="bookmap" type="book">
        <id property="bookId" column="bookid"/>
        <result property="bookName" column="bookname"/>
    </resultMap>
    <select id="getAllBooks" resultMap="bookmap">
        select bookid,bookname from book
    </select>

四、深入---一对多、多对一关系处理

首先需要说明的是:

            复杂的属性,我们需要单独处理:
                对象:association
                集合:collection

建表:

create table stu(
    id int primary key auto_increment,
    name varchar(20),
    gender varchar(2)
);

create table class(
    id int primary key,
    stuId int,
    classId int,
    constraint fk_stu_id foreign key (stuId) references stu (id)
);

insert into stu(id,name,gender) values(1001,'李信','男'),(1002,'安琪拉','女'),(1003,'李白','男'),(1004,'澜','男');

insert into class(id,stuId,classId) values(1,1001,1),(2,1002,2),(3,1003,2),(4,1004,1);

创建实体类:

Stu:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Stu {
    private int id;
    private String name;
    private String gender;
    private Class aClass;
}

Class:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Class {
    private int id;
    private int stuId;
    private int classId;
    private List<Stu> stus;
}

4.1 一对多关系处理

接口:

public interface ClassMapper {
    List<Class> getClassById(int classId);
}

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="mapper.ClassMapper">
    <!--
        mapper接口和映射文件要保证两个一致:
        1.mapper接口的全类名和映射文件的namespace一致
        2.mapper接口中的方法的方法名要和映射文件中的sql的id保持一致
    -->
    <resultMap id="classmap" type="Class">
        <id property="id" column="id"/>
        <result property="stuId" column="stuId"/>
        <result property="classId" column="classId"/>
        <collection property="stus" ofType="stu">
            <id property="id" column="id"/>
            <result property="name" column="name"/>
            <result property="gender" column="gender"/>
        </collection>
    </resultMap>

    <select id="getClassById" resultMap="classmap" parameterType="int">
        select class.id,class.stuId,class.classId,stu.id,stu.name,stu.gender from class left outer join stu on class.stuId=stu.id where classId=#{classId}
    </select>

</mapper>

测试:

    @Test
    public void testGetClassById(){
        ClassMapper mapper = sqlSession.getMapper(ClassMapper.class);
        List<Class> list = mapper.getClassById(1);
        list.forEach(System.out::println);
    }

运行截图:

总结:

一对多关系使用collection标签,ofType属性

4.2 多对一关系处理

接口:

public interface StuMapper {

    Stu getStuById(int id);
}

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="mapper.StuMapper">
    <!--
        mapper接口和映射文件要保证两个一致:
        1.mapper接口的全类名和映射文件的namespace一致
        2.mapper接口中的方法的方法名要和映射文件中的sql的id保持一致
    -->
    <resultMap id="stumap" type="Stu">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="gender" column="gender"/>
        <association property="aClass" javaType="Class">
            <id property="id" column="id"/>
            <result property="stuId" column="stuId"/>
            <result property="classId" column="classId"/>
        </association>
    </resultMap>
    <select id="getStuById" resultMap="stumap" parameterType="int">
        select stu.id,stu.name,stu.gender,class.id,class.classId from stu left outer join class on stu.id=class.stuId where stu.id=#{id}
    </select>
</mapper>

测试:

    @Test
    public void testGetStuById(){
        StuMapper mapper = sqlSession.getMapper(StuMapper.class);
        Stu stu = mapper.getStuById(1001);
        System.out.println(stu);
    }

运行截图:


至此,mybatis大部分场景你都可以轻松应对了,恭喜~~❀❀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值