目录

一.新增

二.修改

三.删除、根据Id查询

1.删除用户

2.根据Id查询

四.模糊查询

1.使用#定义参数

 2.使用$定义参数

五.分页查询

1.顺序传参

2.@Param传参

3.POJO传参

4.Map传参

六.聚合查询

七.主键回填


一.新增

通过Navicat查看数据库,右键user表,点击设计表,可以看到表的各种设置

mybatis mysql插入优化 mybatis添加数据_sql

可以看到user表的id列是自增的,也就是插入数据时不需要设置id字段!

mybatis mysql插入优化 mybatis添加数据_javaEE_02

在接口文件里定义插入接口函数

mybatis mysql插入优化 mybatis添加数据_mybatis mysql插入优化_03

 然后在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">

<!--        namespace设置映射的文件-->
<mapper namespace="com.first.mapper.UserMapper">
<!--
    id是方法名;
    resultType表示结果的对象,即列表的泛型;
    查找用select标签 -->
    <select id="findAll" resultType="com.first.pojo.User">
        select * from user
    </select>
<!--    在values中传入对象的属性时就把属性放到#{}中-->
    <insert id="add" parameterType="com.first.pojo.User">
        insert into user (username,sex,address) values (#{username},#{sex},#{address})
    </insert>
</mapper>

不必在SqlMapConfig.xml中再配置了,因为之前已经配置过映射文件。

在User.java中再添加一个三个参数的构造函数,因为插入时不用插入id字段

public User(String username, String sex, String address) {
    this.username = username;
    this.sex = sex;
    this.address = address;
}

编写测试方法 ,在 测试类里添加如下方法:

@Test
    public void testAdd() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        SqlSession session = factory.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);

        User user=new User("塔姆","男","西安");
        userMapper.add(user);

        //提交事务,增删改都需要提交事务,否则数据库不会改变
        session.commit();
        //释放资源
        session.close();
        is.close();
    }


注意:


  • 当接口方法的参数类型为POJO类型时,SQL语句中绑定参数时使用 #{POJO的属性名} 即可。
  • MyBatis事务默认手动提交,所以在执行完增删改方法后,需要手动调用SqlSession对象的事务提交方法,否则数据库将不发生改变。

运行测试方法,也要看到数据库里插入成功!

mybatis mysql插入优化 mybatis添加数据_增删改查_04

二.修改


优化测试类


我们发现 MyBatis 的测试方法在操作数据库前都需要获取代理对象,操作数据库后都需要释放资源,可以利用 Junit 的 前置后置方法 ,优化测试类代码。



这样Junit就会自动执行获取代理对象和释放资源的方法。 新建一个TestUserMapper2.java测试类,利用前置和后置将公共部分取出,降低代码冗余度。

package com.first.mapper;

import com.first.pojo.User;
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 java.io.IOException;
import java.io.InputStream;

public class TestUserMapper2 {
    //全局变量
    InputStream is=null;
    SqlSession session =null;
    UserMapper userMapper =null;

    //前置方法:测试类里的测试方法执行之前都会先执行前置方法
    @Before
    public void before() throws IOException {
        //(1)读取核心配置文件
        is= Resources.getResourceAsStream("SqlMapConfig.xml");
        //(2)创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //(3)SqlSessionFactoryBuilder对象获取SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(is);
        //(4)SqlSessionFactory对象获取SqlSession对象
        session = factory.openSession();
        //(5)SqlSession对象获取代理对象
        userMapper = session.getMapper(UserMapper.class);
    }

    后置方法:测试类里的测试方法执行之后都会执行后置方法
    @After
    public void after() throws IOException {
        //(7)释放资源
        session.close();
        is.close();
    }

}

在UserMapper.java中添加接口函数:

//修改数据
void update(User user);

在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">

<!--        namespace设置映射的文件-->
<mapper namespace="com.first.mapper.UserMapper">
    <!--
        id是方法名;
        resultType表示结果的对象,即列表的泛型;
        查找用select标签 -->
    <select id="findAll" resultType="com.first.pojo.User">
        select *
        from user
    </select>
    <!--    在values中传入对象的属性时就把属性放到#{}中-->
    <!--    参数类型是User对象-->
    <insert id="add" parameterType="com.first.pojo.User">
        insert into user (username, sex, address)
        values (#{username}, #{sex}, #{address})
    </insert>
    <update id="update" parameterType="com.first.pojo.User">
        update user
        set username=#{username},
            sex=#{sex},
            address=#{address}
        where id = #{id}
    </update>
</mapper>

编写测试函数:

package com.first.mapper;

import com.first.pojo.User;
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 java.io.IOException;
import java.io.InputStream;

public class TestUserMapper2 {
    //全局变量
    InputStream is=null;
    SqlSession session =null;
    UserMapper userMapper =null;

    //前置方法:测试类里的测试方法执行之前都会先执行前置方法
    @Before
    public void before() throws IOException {
        //(1)读取核心配置文件
        is= Resources.getResourceAsStream("SqlMapConfig.xml");
        //(2)创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //(3)SqlSessionFactoryBuilder对象获取SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(is);
        //(4)SqlSessionFactory对象获取SqlSession对象
        session = factory.openSession();
        //(5)SqlSession对象获取代理对象
        userMapper = session.getMapper(UserMapper.class);
    }

    后置方法:测试类里的测试方法执行之后都会执行后置方法
    @After
    public void after() throws IOException {
        //(7)释放资源
        session.close();
        is.close();
    }

    @Test
    public void testUpdate(){
        User user = new User(7,"吉米","女","深圳");
        userMapper.update(user);
        session.commit();
    }
}

运行:

看到数据库已经更新

mybatis mysql插入优化 mybatis添加数据_sql_05

三.删除、根据Id查询

1.删除用户

在UserMapper.java中添加接口函数:

//删除用户
void delete(int userId);

 在UserMapper.xml中配置映射:

<delete id="delete" parameterType="int">
        delete
        from user
        where id = #{sbID}
    </delete>


注:当方法的参数类型是简单数据类型时, #{} 中可以写任意名称 ,就像形参那样,叫啥都行,比如我这里叫了sbID


简单数据类型:基本数据类型、字符串等



编写测试方法 :




@Test
    public void testDelete(){
        userMapper.delete(7);
        session.commit();
    }

运行发现果然删除成功!


2.根据Id查询

在UserMapper.java中添加接口函数:

//根据id查找用户
User findById(int userId);

 在UserMapper.xml中配置映射:

参数是用户的id,是int类型(故而参数名随便起了个userId),返回的结果是一个用户对象,类型是User

<select id="findById" parameterType="int" resultType="com.first.pojo.User">
        select * from user where id=#{userId}
    </select>

编写测试方法 :

@Test
    public void testFindById(){
        //查询操作没有修改数据库,不用提交事务
        User user = userMapper.findById(1);
        System.out.println(user);
    }

输出:

User{id=1, username='小热', sex='男', address='北京'}

四.模糊查询

1.使用#定义参数

在UserMapper.java中添加接口函数(即持久层接口添加方法):

//根据用户名进行模糊查询
List<User> findByUsernameLike(String username);

映射文件添加标签 )

<!--    注意parameterType是小写的string,另一种写法是java.lang.String-->
    <select id="findByUsernameLike" parameterType="string" resultType="com.first.pojo.User">
        select * from user where username like #{username}
    </select>

编写测试方法 :

@Test
    public void testFindByUsernameLike(){
        List<User> users=userMapper.findByUsernameLike("%小%");
        users.forEach(System.out::println);
    }

运行:

名字里带小的都能查询出来

User{id=1, username='小热', sex='男', address='北京'}
User{id=2, username='小巴', sex='男', address='上海'}
User{id=3, username='小赵', sex='女', address='广州'}
User{id=4, username='小迪', sex='男', address='北京'}
User{id=5, username='小丽', sex='男', address='太原'}


我们看到在映射文件中, parameterType 的值为 string 而没有写 java.lang.String ,这是为什么呢?


参数 / 返回值类型为基本数据类型 / 包装类 /String 等类型时,我们可以写全类名,也可以写别名。


mybatis mysql插入优化 mybatis添加数据_javaEE_06

 

mybatis mysql插入优化 mybatis添加数据_增删改查_07

 2.使用$定义参数


模糊查询如果不想在调用方法时参数加 % ,可以使用拼接参数的方式设置 Sql :


<select id="findByUsernameLike" parameterType="string" resultType="com.first.pojo.User">
        select * from user where username like '%${value}%'
    </select>

测试方法写法如下:

@Test
    public void testFindByUsernameLike(){
        List<User> users=userMapper.findByUsernameLike("小");
        users.forEach(System.out::println);
    }

运行测试方法,发现运行成功,名字里带“小”的用户信息都被查出!


#和$ 的区别:


  1. 1 #表示sql模板的占位符,$表示将字符串拼接到sql模板中。
  2. 2 #可以防止sql注入(相当于学JDBC时的PreparedStatement),一般能用#就不用$(相当于学JDBC时的Statement)。
  3. 3 ${}内部的参数名必须写value。

使用 <bind> 定义参数


如果使用 # 还不想在调用方法的参数中添加 % ,可以使用 <bind> , <bind> 允许我们在 Sql 语句以外创建一个变量,并可以将其绑定到当 前的 Sql 语句中。用法如下:



<select id="findByUsernameLike" parameterType="string" resultType="com.first.pojo.User">
        <bind name="likeName" value="'%'+username+'%'"/>
        select * from user where username like #{likeName}
    </select>

测试方法写法如下:

@Test
    public void testFindByUsernameLike(){
        List<User> users=userMapper.findByUsernameLike("小");
        users.forEach(System.out::println);
    }

 运行结果和上面一致!

五.分页查询

mybatis mysql插入优化 mybatis添加数据_mybatis_08


分页查询时, Sql 语句使用 limit 关键字,需要传入开始索引和每页条数两个参数。 MyBatis 的多参数处理有以下方式:



1.顺序传参


Sql 中的参数使用 arg0 , arg1... 或 param1 , param2... 表示参数的顺序。 此方法可读性较低,在开发中不建议使用。



持久层接口方法 :



//下面的注释先把接口函数写完,然后在函数上一行打出/**然后回车就出来了
    /**
     *
     * @param startIndex 开始索引
     * @param pageSize 每页条数
     * @return
     */
    List<User> findPage(int startIndex,int pageSize);


映射文件 :



<!--多个参数时就没必要设置parameterType,因为参数类型可能不同-->
<!--    其中arg0,arg1也可以换成param1和param2-->
    <select id="findPage" resultType="com.first.pojo.User">
        select * from user limit #{arg0},#{arg1}
    </select>


测试类 :


@Test
    public void testFindPage(){
        List<User> users = userMapper.findPage(0, 3);
        users.forEach(System.out::println);
    }

运行测试方法:

User{id=1, username='小热', sex='男', address='北京'}
User{id=2, username='小巴', sex='男', address='上海'}
User{id=3, username='小赵', sex='女', address='广州'}

2.@Param传参



在接口方法的参数列表中通过 @Param 定义参数名称,在 Sql 语句中通过注解中所定义的参数名称指定参数位置。 此方式参数比较直观的,推荐使用。



1



持久层接口方法 :



/**
* 
* @param startIndex 开始索引
* @param pageSize 每页条数
* @return
*/
//推荐注解名和参数名一致,这样可读性高
List<User> findPage1(@Param("startIndex") int startIndex, @Param("pageSize") int pageSize);


映射文件 :



<!--    直接传入参数对应的注解名-->
    <select id="findPage1" resultType="com.first.pojo.User">
        select * from user limit #{startIndex},#{pageSize}
    </select>



测试类 :





@Test
    public void testFindPage1(){
        List<User> users = userMapper.findPage1(3, 3);
        users.forEach(System.out::println);
    }

运行测试方法:

User{id=4, username='小迪', sex='男', address='北京'}
User{id=5, username='小丽', sex='男', address='太原'}
User{id=6, username='本本', sex='男', address='西安'}

3.POJO传参



自定义 POJO 类,该类的属性就是要传递的参数,在 SQL 语句中绑定参数时使用 POJO 的属性名作为参数名即可。 此方式推荐使用。



1



自定义 POJO :




在src/main/java/com/first/pojo/下创建PageQuery类




package com.first.pojo;

public class PageQuery {
    private int startIndex;
    private int pageSize;

    public PageQuery() {
    }

    public PageQuery(int startIndex, int pageSize) {
        this.startIndex = startIndex;
        this.pageSize = pageSize;
    }

    public int getStartIndex() {
        return startIndex;
    }

    public void setStartIndex(int startIndex) {
        this.startIndex = startIndex;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
}



持久层接口方法 :




/**
* 分页查询
*/
//参数是一个类对象
List<User> findPage2(PageQuery pageQuery);



映射文件:




<!--    pojo传参-->
    <select id="findPage2" resultType="com.first.pojo.User" parameterType="com.first.pojo.PageQuery">
        select * from user limit #{startIndex},#{pageSize}
    </select>


测试函数:

@Test
    public void testFindPage2(){
        PageQuery pageQuery=new PageQuery(3,3);
        List<User> users = userMapper.findPage2(pageQuery);
        users.forEach(System.out::println);
    }

运行:

User{id=4, username='小迪', sex='男', address='北京'}
User{id=5, username='小丽', sex='男', address='太原'}
User{id=6, username='本本', sex='男', address='西安'}

4.Map传参


如果不想自定义 POJO ,可以使用 Map 作为传递参数的载体,在 SQL语句中绑定参数时使用 Map 的 Key 作为参数名即可。 此方法推荐使用。


1


持久层接口方法:



//参数是一个Map对象
List<User> findPage3(Map<String,Object> params);




映射文件 :



<select id="findPage3" resultType="com.first.pojo.User" parameterType="map">
     select * from user limit #{startIndex},#{pageSize}
</select>

测试函数:

@Test
    public void testFindPage3(){
        Map<String,Object> params = new HashMap();
        params.put("startIndex",0);
        params.put("pageSize",4);
        List<User> users = userMapper.findPage3(params);
        users.forEach(System.out::println);
    }

运行:

User{id=1, username='小热', sex='男', address='北京'}
User{id=2, username='小巴', sex='男', address='上海'}
User{id=3, username='小赵', sex='女', address='广州'}
User{id=4, username='小迪', sex='男', address='北京'}


在MyBatis中使用Map传参,Map键的类型为: String

六.聚合查询

举例:查询用户总数


持久层接口方法:



int findCount();



映射文件 :


<select id="findCount" resultType="int">
   select count(id) from user
</select>



测试方法:




@Test
    public void testFindCount(){
        System.out.println(userMapper.findCount());
    }

运行输出:

7


七.主键回填


有时我们需要获取新插入数据的主键值。如果数据库中主键是自增的,这时我们就需要使用 MyBatis 的主键回填功能。


1


持久层接口方法:



void add2(User user);



映射文件:




<insert id="add2" parameterType="com.first.pojo.User">
        <!-- keyProperty:主键属性名,keyColumn:主键列名,resultType:主键类型,
        order:执行时机,AFTER是代表在插入之后执行 -->
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
         SELECT LAST_INSERT_ID();
        </selectKey>
        insert into user(username,sex,address)
        values(#{username},#{sex},#{address})
    </insert>



SELECT LAST_INSERT_ID():查询刚刚插入的记录的主键值,只适用于自增主键,且必须和insert语句一起执行。


测试方法:

主键回填即自动递增的逐渐不止体现在数据库中,咱们new的user对象起初并没有赋id值,所以主键回填就是把自动生成的主键回填到user对象的id值上!

@Test
    public void testAdd2(){
        User user = new User("丽颖", "女", "南京");
        //如果换成最开始写的add()函数,那么返回值是0
        userMapper.add2(user);
        session.commit();
        System.out.println(user.getId());
    }

运行:

9

到此为止的项目结构如下:

mybatis mysql插入优化 mybatis添加数据_mybatis mysql插入优化_09