mybatis

简介

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

基本使用

  1. 首先引入jar包
<!--jar包依赖-->
    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>

        <!--junit测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>

        <!--log4j日志-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
  1. 我们以一个用户的增删查改为例子
    创建一个java实体类user对象
public class User {
    private Integer id;
    private String name;
    private String password;
    private char sex;
    private String email;

    public User() {
    }

    public User(Integer id, String name, String password, char sex, String email) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.sex = sex;
        this.email = email;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", sex=" + sex +
                ", email='" + email + '\'' +
                '}';
    }
}

设置好getter setter方法

  1. mapper接口
public interface UserMapper {

    /**
     * 添加一个用户
     */
    int insertUser();

    /**
     * 更新一个用户
     */
    int updateUser();

    /**
     * 删除一个用户
     */
    int deleteUser();

    /**
     * 根据id号查询用户
     */
    User getUserById(Integer id);

    /**
     * 获取所有user
     */
    List<User> getAllUser();
}
  1. 创建数据库,和user对应的表 以便下面我们对他进行增删查改

5.下面就是创建mybatisConfig配置文件

<?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>

    <!--引入配置文件-->
    <properties resource="jdbc.properties"/>

    <!--
        设置类型别名
        类型别名不区分大小写
        alias可以设置可以不设置 当不设置alias时 alias默认为class的名称 user不去区分大小写
    -->
    <typeAliases>
        <typeAlias type="cn.luoyudi.mybatis.pojo.User" alias="User"/>

        <!--扫描包下面的所有类型 设置包名 以包为单位 将包下 所有的类型都设置为默认的类型名称 即类名不区分大小写-->
        <package name="cn.luoyudi.mybatis.pojo"/>
    </typeAliases>

    <!--配置连接数据库的环境-->
    <environments default="development">
        <!--设置环境-->
        <environment id="development">
            <!--
                事务管理 存在两个值'jdbc'表示当前环境中,使用的是jdbc的事务管理方式
                                'managed' 表示被管理
            -->
            <transactionManager type="JDBC"/>
            <!--
                数据源设置
                    POOLED表示使用数据库连接池
                    unPOOLED表示不使用数据库连接池
                    jndi使用上下文中配置的连接池
            -->
            <dataSource type="POOLED">
                <!--使用${}引用配置文件中的value-->
                <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>
    <!--引入映射文件-->
    <mappers>
        <!--<mapper resource="mapper/UserMapper.xml"/>-->

        <!--以包为单位扫描
            注意mapper.xml映射文件需要在接口同目录下并且名称一致
        -->
        <package name="cn.luoyudi.mybatis.mapper"/>
    </mappers>
</configuration>
  1. 配置mapper.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">
<!--绑定UserMapper-->
<mapper namespace="cn.luoyudi.mybatis.mapper.UserMapper">

    <!--int insertUser();-->
    <insert id="insertUser">
        insert into t_user
        values (null, 'admin', 'admin', '男', 'admin@qq.com');
    </insert>

    <!--int updateUser();-->
    <update id="updateUser">
        update t_user
        set name = '张三'
        where id = 2;
    </update>

    <!--int deleteUser();-->
    <delete id="deleteUser">
        delete
        from t_user
        where id = 3;
    </delete>

    <!--User getUserById(Integer id);-->
    <select id="getUserById" resultType="cn.luoyudi.mybatis.pojo.User">
        select *
        from t_user
        where id = 2;
    </select>

    <!--List<User> getAllUser();-->
    <select id="getAllUser" resultType="User">
        select *
        from t_user;
    </select>
</mapper>
  1. 测试方法
    @Test
    public void insertUser() throws IOException {

        //加载核心配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //获取sqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //获取sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        //获取sqlSession                          自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取mapper接口对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.insertUser();

        //sqlSession.commit();

        System.out.println(i);

    }

mybatis工作流程

  1. 加载配置文件
  2. sqlSessionFactoryBuilder.build(inputStream);读取配置文件,新建一个sqlSession工厂
  3. sqlSessionFactory.openSession();工厂生产sqlsession
  4. sqlSession.getMapper(UserMapper.class);从sqlsession中传递接口的class,获取对应的mapper,
  5. mapper直接调用方法,就可以直接实现方法

在这个过程中,mybatis帮助我们创建了userMapperImpl对象,并且帮我们生成sql对应的方法,实现功能

各种查询操作

根据id查询用户信息

    /**
     * 根据id查询用户信息
     */
    User selectUserById(@Param("id") Integer id);
    <!--User selectUserById(Integer id);-->
    <select id="selectUserById" resultType="user">
        select *
        from t_user
        where id = #{id};
    </select>

在简单的查询中,向sql语句中传递单个参数可以不用带@Param() 但是,为了记忆方便,我们都带上这个注解
在这个注解中配置的名称,就是在sql语句中引用的名称#{id};
resultType属性,是设置查询语句返回值而设定的属性,查询返回值是user对象,那就设置成user,前提是需要在mybatisConfig核心文件中配置

    <typeAliases>
        <package name="cn.luoyudi.mybatis.pojo"/>
    </typeAliases>

这个属性就是设置实体类的别名使用的,因为如果不设置别名,他的引用就是实体类的全类名,非常长,所以我们使用设置别名,在这个属性中可以设置扫描包,也可以单个设置类名,在实体类上注明@Alias()注解就可以自定义起名,默认扫到的名称为首字母小写名称如User->user

查询所有用户信息

    /**
     * 查询所有用户信息
     */
    List<User> getAllUser();
    <!--List<User> getAllUser();-->
    <select id="getAllUser" resultType="user">
        select *
        from t_user;
    </select>

查询所有用户信息与上面的查询方法相同,

查询表中的总记录数

    /**
     * 查询表中的总记录数
     */
    Integer getCount();
    <!--Integer getCount();-->
    <select id="getCount" resultType="java.lang.Integer">
        select count(*)
        from t_user;
    </select>

查询结果条数返回的是一个integer类型的数字,所以resultType属性应当配置integer类型的全类名
值得要说的是,在mybatis初始化的时候,自动给我们设置了一些别名
在这里插入图片描述
在这里插入图片描述
如上图,所以这里也可以直接写作int

根据id查询用户的信息为一个map集合

    /**
     * 根据id查询用户的信息为一个map集合
     */
    Map<String, Object> getUserMapById(@Param("id") Integer id);
    <!--Map<String, Object> getUserMapById(@Param("id") Integer id);-->
    <select id="getUserMapById" resultType="map">
        select *
        from t_user
        where id = #{id};
    </select>

就是将查询到的用户字段名为键字段值为键的值,
我们设置了一个map集合当作返回结果,这里使用的就是map集的别名,

获取所有用户都作为map

    /**
     * 获取所有用户都作为map
     */
    //List<Map<String, Object>> getAllUserToMap();
    @MapKey("id")
    Map<String, Object> getAllUserToMap();
    <!--List<Map<String, Object>> getAllUserToMap();-->
    <select id="getAllUserToMap" resultType="map">
        select *
        from t_user;
    </select>

这里查询到所有用户都作为map集合,并且将查询到的用户放在一个list集合中返回值需要改成List<Map<String, Object>>
或者另一种方式@MapKey()注解返回值仍然可以是Map<String, Object>此时,mybatis就会自己把我们配在注解中的属性的值当键,以键对应的查询结果为值放在新的map集合中
类似于@MapKey(“id”)Map<id字段对应的值,Map<String, Object>>

根据用户名进行模糊查询

    /**
     * 根据用户名模糊查询
     */
    List<User> getUserByLike(@Param("username") String str);
    <!--List<User> getUserByLike(String str);-->
    <select id="getUserByLike" resultType="user">
        select *
        from t_user
--         where name like '%${username}%';
        where name like concat('%',
        #{username},
        '%'
        );
    </select>

实现模糊查询,有两种sql语句可以使用一个使用#{}一个使用${}

首先说一下两种方式的区别
他们都可以取值,但是两种方式的区别是,#{}是预编译的,${}本质是占位符有sql注入的隐患
所以能使用#{}一定要使用#{},
先介绍使用${}的方式 ‘%${username}%’;直接拼接在like后面%%通配符,直接查询

然后是#{},使用#{}时因为我们是预编译,所以使用上面的写法会出现问题,此时我们要使用#{}可以使用mysql中的字符串拼接函数concat()将#{}和通配符相拼接

批量删除

    /**
     * 批量删除
     */
    int deleteMoreUser(@Param("ids") String ids);
    <!--int deleteMoreUser(@Param("ids") String ids);-->
    <delete id="deleteMoreUser">
        delete
        from t_user
        where id in (${ids});
    </delete>

使用批量删除时,如果我们单独调用删除一条的语句需要循环好多次,会降低我们效率,所以使用mysql中的in语法,直接传递进去一个字符串,字符串里面的都直接删除

查询指定表中的数据

    /**
     * 查询指定表中的数据
     */
    List<User> getUserByTableName(@Param("tableName") String tableName);
    <!--List<User> getUserByTableName(@Param("tableName") String tableName);-->
    <select id="getUserByTableName" resultType="user">
        select *
        from ${tableName};
    </select>

查询表中的数据,直接输入进去表名即可

上面就是一些基本的操作实例

多对一和一对多关系

处理多对一映射关系

  1. 级联属性
 <resultMap id="empAndDeptResultMap_1" type="emp">
     <result property="dept.did" column="did"/>
     <result property="dept.deptName" column="dept_name"/>
 </resultMap>

不一样的属性全部配置到映射里面

  1. 使用association标签
    association专门处理多对一关系,需要把属性单独配置出来,写法上与上面的方式几乎一样 只是多一个标签
    只是使用association后,所有属性都需要进行映射
 <resultMap id="empAndDeptResultMap_2" type="emp">
     <id property="eid" column="eid"/>
     <result property="empName" column="emp_name"/>
     <result property="age" column="age"/>
     <result property="sex" column="sex"/>
     <result property="email" column="email"/>
     <!--property需要处理的属性名 javaType是实体类对象-->
     <association property="dept" javaType="dept">
         <id property="did" column="did"/>
         <result property="deptName" column="dept_name"/>
     </association>
 </resultMap>
  1. 分步查询
 <!--Emp getEmpAndDeptBySept_1(@Param("eid") Integer eid);-->
 <select id="getEmpAndDeptBySept_1" resultMap="getEmpAndDeptBySeptResultMap_1">
     select *
     from t_emp
     where eid = #{eid};
 </select>
 <resultMap id="getEmpAndDeptBySeptResultMap_1" type="emp">
     <!--
     select : 设置第二部查询sql语句唯一标识  类名加上方法名
     column : 分布查询第二部的条件
     -->
     <association property="dept"
                  select="cn.luoyudi.mybatis.mapper.DeptMapper.getEmpAndDeptBySept_2"
                  column="did"/>
 </resultMap>

处理一对多映射关系

动态sql

当sql语句where后面的条件语句有时满足有时不满足时,我们可以使用if标签,当满足text属性中的条件时,if中的语句会被粘贴在前面的语句后,当不满足条件时,将不会有效

 <select id="getEmpByCondition_1" resultType="emp">
     select * from t_emp where 1=1
     <if test="empName != null and empName != ''">
         and emp_name = #{empName}
     </if>
     <if test="age!=null and age!=''">
         and age = #{age}
     </if>
     <if test="sex != null and sex!=''">
         and sex = #{sex}
     </if>
     <if test="email != null and email != ''">
         and email = #{email}
     </if>
 </select>

并且,为了语句不报错,需要在where后面加入一条恒成立的条件比如1=1

现在就可以动态生成sql语句了,但是仍然不太满足,因为where后面的条件冗余,所以有另外的标签,解决这个问题
where标签

 <select id="getEmpByCondition_2" resultType="emp">
     select * from t_emp
     <where>
         <if test="empName != null and empName != ''">
             and emp_name = #{empName}
         </if>
         <if test="age!=null and age!=''">
             and age = #{age}
         </if>
         <if test="sex != null and sex!=''">
             and sex = #{sex}
         </if>
         <if test="email != null and email != ''">
             and email = #{email}
         </if>
     </where>
 </select>

可以看到,这时的语句减少了where后面的1=1,并且可以删除语句之前的and或者or,非常好用

接下来的标签,可以自定义把语句中前面或者后面添加或者删除指定的字符

 <select id="getEmpByCondition" resultType="emp">
     select * from t_emp
     <trim prefix="" suffix="" prefixOverrides="" suffixOverrides="">
         <if test="empName != null and empName != ''">
             and emp_name = #{empName}
         </if>
         <if test="age!=null and age!=''">
             and age = #{age}
         </if>
         <if test="sex != null and sex!=''">
             and sex = #{sex}
         </if>
         <if test="email != null and email != ''">
             and email = #{email}
         </if>
     </trim>
 </select>

trim中有四个标签
prefix|suffix : 在语句前后添加指定语句
prefixOverrides|suffixOverrides : 在语句前后删除指定语句

例:

 <select id="getEmpByCondition" resultType="emp">
     select * from t_emp
     <trim prefix="where" prefixOverrides="and|or">
         <if test="empName != null and empName != ''">
             and emp_name = #{empName}
         </if>
         <if test="age!=null and age!=''">
             and age = #{age}
         </if>
         <if test="sex != null and sex!=''">
             and sex = #{sex}
         </if>
         <if test="email != null and email != ''">
             and email = #{email}
         </if>
     </trim>
 </select>

逆向工程

逆向工程是根据表中的字段名称,自动生成java实体类的过程叫逆向工程,就是根据表生成实体类,简化了写实体类的过程

  1. 首先先添加依赖 在pom文件中添加生成类的插件
<!-- 控制Maven在构建过程中相关配置 -->
    <build>
        <!-- 构建过程中用到的插件 -->
        <plugins>
            <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.0</version>
                <!-- 插件的依赖 -->
                <dependencies>
                    <!-- 逆向工程的核心依赖 -->
                    <dependency>
                        <groupId>org.mybatis.generator</groupId>
                        <artifactId>mybatis-generator-core</artifactId>
                        <version>1.3.2</version>
                    </dependency>
                    <!-- 数据库连接池 -->
                    <dependency>
                        <groupId>com.mchange</groupId>
                        <artifactId>c3p0</artifactId>
                        <version>0.9.2</version>
                    </dependency>
                    <!-- MySQL驱动 -->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.27</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
  1. 另外就是需要配置逆向工程的配置文件 并且 文件名称必须是generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
    targetRuntime: 执行生成的逆向工程的版本
    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
    MyBatis3: 生成带条件的CRUD(奢华尊享版)
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis"
                        userId="root"
                        password="mysql">
        </jdbcConnection>
        <!-- javaBean的生成策略  生成路径-->
        <javaModelGenerator targetPackage="cn.luoyudi.mybatis.pojo" targetProject=".\src\main\java">
            <!--是否能够使用子包->多层目录-->
            <property name="enableSubPackages" value="true" />
            <!--去掉字符串前后的空格-->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="cn.luoyudi.mybatis.mapper" targetProject=".\src\main\resources">
            <!--子包-->
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="cn.luoyudi.mybatis.mapper" targetProject=".\src\main\java">
            <!--子包-->
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>

文件内部主要包括文件生成位置,配置表的名称,
以及生成策略,包括两种,一种是比较简洁的MyBatis3Simple策略,一种是比较豪华的MyBatis3策略

配置好之后需要执行插件生成实体类以及mapper映射文件插件名称为generate,双击运行
在这里插入图片描述
运行后就会在配置好的路径下生成文件,简洁版会生成实体类,mapper文件,豪华版还会生成实体类对应的example条件构建类
在执行有条件的查询语句时,就需要new一个对应的实体类的example对象进行配置,支持链式编程

    @Test
    public void testMBG() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //List<Emp> empList = mapper.selectByExample(null);
        //empList.forEach(System.out::println);

        EmpExample example = new EmpExample();
        example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThan(20);
        example.or().andDidIsNotNull();
        List<Emp> empList = mapper.selectByExample(example);
        empList.forEach(System.out::println);
    }

测试方法

分页插件pagehelper

分页插件主要是为了解决在分页时需要的包括页数,总记录数,页码等等信息需要自己计算出来,非常麻烦,为了解决上面的问题,需要分页插件,分页插件可以生成很多我们分页时的数据,直接调用即可

  1. 首先先导入xml配置文件
    <dependencies>
        <!--pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.0</version>
        </dependency>
    </dependencies>
    @Test
    public void textPageHelper() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //开启分页
        //Page<Object> page = PageHelper.startPage(3, 3);
        Page<Object> page = PageHelper.startPage(3, 3);
        List<Emp> emps = mapper.selectByExample(null);

        //获取更多数据
        PageInfo<Emp> pageInfo = new PageInfo<>(emps, 5);

        //emps.forEach(System.out::println);
        System.out.println(pageInfo);
    }

常用数据 :

  1. pageNum:当前页的页码
  2. pageSize:每页显示的条数
  3. size:当前页显示的真实条数
  4. total:总记录数
  5. pages:总页数
  6. prePage:上一页的页码
  7. nextPage:下一页的页码
  8. isFirstPage/isLastPage:是否为第一页/最后一页
  9. hasPreviousPage/hasNextPage:是否存在上一页/下一页
  10. navigatePages:导航分页的页码数
  11. navigatepageNums:导航分页的页码,[1,2,3,4,5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值