MyBatis

MyBatis快速入门

MyBatis中文网文档:https://mybatis.org/mybatis-3/zh/index.html

开发步骤:

①添加MyBatis的坐标和mysql的坐标,即安装。

②创建数据表

③编写实体类

④编写映射文件

⑤编写核心文件

⑥编写测试类

安装

要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于类路径(classpath)中即可。

如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:

mybatis依赖

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.5</version>
</dependency>

mysql依赖

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.20</version>
</dependency>

创建数据表

数据表test如下图:

编写实体类Test

package org.lowell.mybatis;

public class Test {
    private Integer id;
    private String name;
    private Integer age;
    private String gender;

    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 Integer getAge() {
        return age;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Test{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

创建持久层的dao接口

定义数据的操作方法

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.List;

// 接口,操作test表
public interface TestDao {

    // 查询test表的所有数据
    public List<Test> selectTests();
}

sql映射文件

sql映射文件就是mybatis使用的配置文件。

作用:用来写sql语句的。一般一个表一个sql映射文件。该文件就是一个xml文件。

sql映射文件在接口所在目录,文件名称和接口类一致。

<?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="org.lowell.dao.TestDao">
    <select id="selectTests" resultType="org.lowell.mybatis.Test">
    select * from Test order by id
    </select>
</mapper>

<!--
sql映射文件:写sql语句的,mybatis会执行sql
1.指定约束文件
    <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    mybatis-3-mapper.dtd是约束文件的名称,扩展名是dtd
    作用:限制、检查在当前文件中出现的标签,属性必须符合mybatis的要求。
2.mapper是当前文件的跟标签
3.namespace:命名空间,唯一值,可以是自定义字符串
    要求:一般都使用dao接口的全限定名称
4.在此xml文件中可以使用特定标签,表示数据库的特定操作,
    如:<select>是查询、<update>更新、<delete>删除、<insert>插入
5.id:要执行的sql语句的唯一标识,mybatis会使用这个id值来找到对应的sql语句。
    可以自定义,但要求使用接口中的方法名称。
6.resultType:表示sql语句执行后,得到的结果集的类型,遍历这个类型得到java对象的类型。
    写类型的权限定名称
-->

编写核心文件

mybatis的主配置文件。一个项目就一个主配置文件。主配置文件放在resources目录下。

主配置文件的作用:提供了数据库的连接信息,和sql映射文件的位置信息。

<?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>
    <!--default和environment中的id一样,从多个地中选一个,证明使用的是那个数据库-->
    <environments default="dev">
        <!-- environment 一个数据库信息的配置
             id 是一个唯一值,表示环境的名称
         -->
        <environment id="dev">
            <!-- transactionManager 是mybatis的事务类型
                 type有两个值:JDBC(使用jdbc中的Connection对象中的commit,rollback做事务处理)
            -->
            <transactionManager type="JDBC"/>
            <!--
            dataSource:表示数据源,连接数据库的
            type:表示数据源类型,POOLED表示连接池
            -->
            <dataSource type="POOLED">
                <!--数据库驱动类名-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--连接数据库的地址-->
                <!--
					注意可能会报错
					Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.0.0:exec (default-cli) on project 01-mybatis: Command execution failed.
					则加上?serverTimezone=GMT%2B8-->
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8"/>
                <!--数据库的用户名-->
                <property name="username" value="root"/>
                <!--数据库的密码-->
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--sql映射文件的位置,一个mapper标签指定一个文件的位置,一般来说就是一个表-->
        <mapper resource="org\lowell\dao\TestDao.xml"/>
    </mappers>
</configuration>

创建使用mybatis的类

通过mybatis访问数据库。

package org.lowell;

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.lowell.mybatis.Test;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        // 访问mybatis读取test数据
        // 1.定义mybatis的主配置文件名称,从类路径根开始(target/classes之后开始写)
        String config = "mybatis.xml";
        // 2.读取config表示的文件
        InputStream inputStream = Resources.getResourceAsStream(config);
        // 3.创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        // 4.创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(inputStream);
        // 5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
        SqlSession sqlSession = factory.openSession();
        // 6.指定要执行sql语句的标识,使用的是sql映射文件中的namespace + "." + 标签的id值
        String sqlId = "org.lowell.dao.TestDao.selectTests";
        // 7.执行sql语句,通过sqlId找到语句
        List<Test> testList = sqlSession.selectList(sqlId);
        // 8.输出结果
        // testList.forEach(test -> System.out.println(test));
        for (Test test : testList) {
            System.out.println(test);
        }
        // 9.关闭
        sqlSession.close();
    }
}

流程描述

  1. 执行上述MyApp类,首先读取mybatis.xml中的数据库信息,创建连接对象,还可以拿到映射文件的位置;
  2. 将sqlId = "org.lowell.dao.TestDao.selectTests"传入执行sql语句的方法,可以到sql映射文件中定位到sql语句的位置。

插入操作

sql映射文件

<?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="org.lowell.dao.TestDao">
    <select id="selectTests" resultType="org.lowell.mybatis.Test">
    select * from test order by id
    </select>
    <insert id="insertTest">
        insert into test values (#{id},#{name},#{age},#{gender})
    </insert>
</mapper>

执行程序

注意:update、delete、insert操作,默认是不提交事务,需要手动提交事务。

也可以设置在动提交,在openSession中设置为true。

package org.lowell;

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.lowell.mybatis.Test;

import java.io.IOException;
import java.io.InputStream;

public class MyApp {
    public static void main(String[] args) throws IOException {
        // 访问mybatis读取test数据
        // 1.定义mybatis的主配置文件名称,从类路径根开始(target/classes之后开始写)
        String config = "mybatis.xml";
        // 2.读取config表示的文件
        InputStream inputStream = Resources.getResourceAsStream(config);
        // 3.创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        // 4.创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(inputStream);
        // 5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
        SqlSession sqlSession = factory.openSession();
        // 6.指定要执行sql语句的标识,使用的是sql映射文件中的namespace + "." + 标签的id值
        String sqlId = "org.lowell.dao.TestDao.insertTest";

        Test test = new Test();
        test.setId(4);
        test.setName("liuweida");
        test.setAge(18);
        test.setGender("男");

        // 7.执行sql语句
        int num = sqlSession.insert(sqlId, test);
        sqlSession.commit();
        // 8. 输出结果
        System.out.println("插入行数:" + num);
        // 9.关闭
        sqlSession.close();
    }
}

使用idea设置模板文件

打开Settings--》File and Code Templates--》+ 号--》输入name和后缀--》将想要保存模板的内容贴进下方窗口中,下次直接创建新文件时,就可以选择创建的模板。

MyBatis动态代理机制

如果不适用动态代理,我们需要自己去实现dao接口中的方法,我们可以直接通过调用方法来执行mybatis数据库操作,使用动态代理我们就不需要自己实现dao接口。

dao接口

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.List;

// 接口,操作test表
public interface TestDao {

    // 查询test表的所有数据
    public List<Test> selectTests();
    // 插入数据的方法名, 返回值是一个int,表示insert之后插入数据库的数据行数
    public int insertTest(Test test);
}

工具类MyBatisUtils

package org.lowell.utils;

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 java.io.IOException;
import java.io.InputStream;

public class MyBatisUtils {
    private static SqlSessionFactory factory = null;
    static {
        String config = "mybatis.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(config);
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession() {
        SqlSession sqlSession = factory.openSession();
        return sqlSession;
    }
}

执行调用文件

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

import java.io.IOException;

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理, 获取对应Dao接口的代理对象
        TestDao dao = sqlSession.getMapper(TestDao.class);

        Test test = new Test();
        test.setId(9);
        test.setName("花无缺");
        test.setAge(18);
        test.setGender("女");
		
        // 通过接口对象调用接口方法
        int num = dao.insertTest(test);
        sqlSession.commit();
        System.out.println("插入行数:" + num);
        sqlSession.close();
    }
}

MyBatis中传递参数

parameterType

从java代码中把数据传递到mapper文件中的sql语句。

parameterType写在mapper中的一个属性。表示dao接口方法中的参数数据类型。该参数可不填。通过反射可以查询到接口参数的类型。

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.List;

public interface TestDao {

    // 查询test表的所有数据
    public List<Test> selectTests();
	// 查询test表的一条数据
    public Test selectTestById(Integer id);
    public int insertTest(Test test);
}

TestDao.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="org.lowell.dao.TestDao">
    <select id="selectTests" resultType="org.lowell.mybatis.Test">
    select * from test order by id
    </select>
    <select id="selectTestById" parameterType="java.lang.Integer" resultType="org.lowell.mybatis.Test">
        select * from test where id=#{id}
    </select>
    <insert id="insertTest">
        insert into test values (#{id},#{name},#{age},#{gender})
    </insert>
</mapper>

一个简单类型的参数

简单类型:mybatis把java的基本数据类型和String、Integer等都叫做简单类型。

在mapper文件中获取一个简单类型的一个参数的值,使用#{任意字符}

<select id="selectTestById" parameterType="java.lang.Integer" resultType="org.lowell.mybatis.Test">
	select * from test where id=#{id}
</select>

一个#{参数},代表了jdbc中的一个?占位符。

多个参数-@Param

语法:

// 接口
    public Test selectMultiParam(@Param("myName") String name, @Param("myAge") Integer age);
// 

sql映射文件

<select id="selectMultiParam" resultType="org.lowell.mybatis.Test">
    select * from test where name=#{myName} or age=#{myAge}
</select>

多个参数-使用对象

多个参数使用java对象的属性值,作为参数的实际值。

语法:#{属性名,javaType=类型名称,jdbcType=数据类型}

  • javaType:指java中属性数据类型

  • jdbcType:在数据库中的数据类型

    #{paramName, javaType=java.lang.String, jdbcType=VARCHAR}
    

简化方法:#{属性名},javaType和jdbcType的值mybatis反射可以获取,不是必须提供。

dao接口层

public List<Test> selectMultiObject(Test test);

java程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);

        Test myTest = new Test();
        myTest.setName("lowell");
        myTest.setAge(18);
        List<Test> tests = dao.selectMultiObject(myTest);
        for (Test test : tests) {
            System.out.println(test.getName());
        }
        sqlSession.close();
    }
}

sql映射文件

<select id="selectMultiObject" resultType="org.lowell.mybatis.Test">
    <!--name和age都是属性名称-->
	select * from test where name=#{name} or age=#{age}
</select>

多个参数-按位置

语法:

mybatis3.4之前使用 #{0},#{1}等

mybatis3.4之后使用#{arg0},#{arg1}

接口

public List<Test> selectMultiPosition(String name, Integer age);

sql映射文件

<select id="selectMultiPosition" resultType="org.lowell.mybatis.Test">
    select * from test where name=#{arg0} or age=#{arg1}
</select>

java程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        List<Test> tests = dao.selectMultiPosition("lowell", 18);
        for (Test test : tests) {
            System.out.println(test.getName());
        }
        sqlSession.close();
    }
}

多个参数-使用Map

语法:

dao持久层文件

public List<Test> selectMultiMap(Map<String, Object> map);

java执行程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        Map<String, Object> data = new HashMap<>();
        data.put("myname","lowell");
        data.put("age",18);
        List<Test> tests = dao.selectMultiMap(data);
        for (Test test : tests) {
            System.out.println(test.getName());
        }
        sqlSession.close();
    }
}

sql映射文件

<select id="selectMultiMap" resultType="org.lowell.mybatis.Test">
    select * from test where name=#{myname} or age=#{age}
</select>

#和&符号的区别

  • 使用?在sql语句中做占位用,使用prepareStatement执行sql语句

  • 能够避免sql注入,更安全

  • &不适用占位符,通过子字符串链接方式,使用Statement对象执行sql,效率低。
  • &有sql注入的风险。
  • &可以替换表名和列名,传值传什么就会使用什么。

resultType

表示结果类型

  • 结果类型,值sql执行完毕之后,数据转为的java对象。

    • mybatis执行sql语句,然后mybatis调用类的无参数构造方法,创建对象。
    • mybatis把ResultSet(遍历)指定列值托付给同名的属性。
    <select id="selectMultiMap" resultType="org.lowell.mybatis.Test">
        select id,name,email,age from test
    </select>
    

    和下面相同

    ResultSet rs = executeQuery("select id,name,email,age from test")
    while (rs.next()) {
        Test test = new Test();  // 调用类的无参数构造方法,创建对象
        test.setId(rs.getInt("id")); // ResultSet(遍历)指定列值托付给同名的属性
    }
    

类型的别名

可以放置全限定名称,也可以放置别名。推荐使用全限定名称。

第一种方式:在mybatis主配置文件中定义,使用定义别名。然后 可以在dao文件中使用

<typeAliases>
    <!--
        type:自定义类型的全限定名称
        alias:别名
        -->
    <typeAlias type="org.lowell.mybatis.Test" alias="test"/>
</typeAliases>

在dao文件中使用别名

<select id="selectMultiMap" resultType="test">
    select * from test where name=#{myname} or age=#{age}
</select>

第二种方式:在mybatis主配置文件中定义,

<typeAliases>
    <!--
        name:是包名,这个包中所有的类,类名就是别名(类名不区分大小写)
        -->
    <package name="org.lowell.mybatis"/>
</typeAliases>

在dao文件中使用

<select id="selectMultiMap" resultType="test">
    select * from test where name=#{myname} or age=#{age}
</select>

推荐使用全限定名称,如果两个包中有一个名称相同的类,那么使用别名会导致不知道使用哪个类。会抛异常。

查询返回Map

注意:返回Map时,只能返回一行数据,多一行会报错。

TestDao.java接口文件

package org.lowell.dao;

import org.apache.ibatis.annotations.Param;
import org.lowell.mybatis.Test;

import java.util.List;
import java.util.Map;

public interface TestDao {

    public Map<Object, Object> selectReturnMap(Integer id);
}

sql映射文件

<select id="selectReturnMap" resultType="java.util.Map">
    select id,name from test where id=#{id}
</select>

java执行程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.utils.MyBatisUtils;

import java.io.IOException;
import java.util.Map;

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        Map<Object, Object> map = dao.selectReturnMap(1);
        System.out.println(map);  // {name=lowell, id=1}
        sqlSession.close();
    }
}

resultMap结果映射

指定列名和java对象的属性对应关系。一般是在列名和java对象属性名不一致时使用。

  1. 先定义resultMap

    将列id赋值给id属性。

    <!--定义resultMap
        id:自定义名称,表示你定义的这个resultMap
        type:java类型的全限定名称
        -->
    <resultMap id="testMap" type="org.lowell.mybatis.Test">
        <!--列名和java属性的关系-->
        <!--
            主键列
            column:列名
            property:java对象的属性名
            -->
        <id column="id" property="id"/>
        <!--
            非主键列 使用result
            -->
        <result column="name" property="name"/>
        <result column="age" property="age"/>
    </resultMap>
    
  2. 使用resultMap

    <select id="selectResultMap" resultMap="testMap">
        select id,name,age,gender from test
    </select>
    
  3. java文件中使用

    package org.lowell;
    
    import org.apache.ibatis.session.SqlSession;
    import org.lowell.dao.TestDao;
    import org.lowell.mybatis.Test;
    import org.lowell.utils.MyBatisUtils;
    
    import java.io.IOException;
    import java.util.List;
    
    public class MyApp {
        public static void main(String[] args) throws IOException {
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
            // 使用mybatis的动态代理
            TestDao dao = sqlSession.getMapper(TestDao.class);
            List<Test> tests = dao.selectResultMap();
            for (Test test : tests) {
                System.out.println(test.getName());
            }
            sqlSession.close();
        }
    }
    

    列名与java对象属性名不一致的情况,可以使用resultMap解决,还可以使用别名的方式解决。

    <select id="selectTest02" resultType="org.lowell.mybatis.Test02">
        select id as myId, name as myName, age as myAge from test
    </select>
    

模糊查询like

第一种方式

将模糊查询字符串传入到sql语句

dao文件

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.List;

public interface TestDao {

    public List<Test> selectLike(String name);
}

sql映射文件

<select id="selectLike" resultType="org.lowell.mybatis.Test">
    select * from test where name like #{name}
</select>

java执行程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        List<Test> tests = dao.selectLike("l%");
        for (Test test : tests) {
            System.out.println(test.getName());
        }
        sqlSession.close();
    }
}

第二种方式

在sql映射文件中拼接like内容

dao文件

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.List;

public interface TestDao {

    public List<Test> selectLike(String name);
}

sql映射文件

<select id="selectLike" resultType="org.lowell.mybatis.Test">
    select * from test where name like #{name} "%"
</select>

java执行程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        List<Test> tests = dao.selectLike("l");
        for (Test test : tests) {
            System.out.println(test.getName());
        }
        sqlSession.close();
    }
}

动态sql

sql内容是变化的,可以根据条件获取到不同的sql语句,主要是where部分发生变化。

动态sql实现,使用的是mybatis提供的标签,, ,

动态sql要使用java对象作为参数。

if标签

用来判断条件的。语法如下:

<if test="使用参数java对象属性值作为判断条件,语法:属性=xxx">

dao文件

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.List;

public interface TestDao {

    public List<Test> selectIf(Test test);
}

sql映射文件

<select id="selectIf" resultType="org.lowell.mybatis.Test">
    <!--使用1=1是为了保证第一个if不成立时防止出现错误
	如果第一个if不成立,那么select * from test where and age > ?会报错。
	如果添加1=1,则select * from test where 1=1 and age > ?语句正确。
	-->
    select * from test where 1=1
    <if test="name != null and name != '' ">
        name=#{name}
    </if>
    <if test="age > 18">
        and age > #{age}
    </if>
</select>

java使用文件

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        Test test = new Test();
        test.setName("lowell");
        test.setAge(17);
        // 动态sql要使用java对象作为参数。
        List<Test> tests = dao.selectIf(test);
        for (Test test1 : tests) {
            System.out.println("-----------" + test1 + "----------");
        }
        sqlSession.close();
    }
}

where标签

用来包含多个的,当多个if有一个成立,<where>会自动增加一个where关键字,并去除if中多余的and和or等。

dao文件

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.List;

public interface TestDao {

    public List<Test> selectIf(Test test);
}

sql映射文件

<select id="selectIf" resultType="org.lowell.mybatis.Test">
    select * from test
    <where>
        <if test="name != null and name != '' ">
            name=#{name}
        </if>
        <if test="age > 18">
            and age > #{age}
        </if>
    </where>
</select>

java执行程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        Test test = new Test();
        test.setAge(17);
        List<Test> tests = dao.selectIf(test);
        for (Test test1 : tests) {
            System.out.println("-----------" + test1 + "----------");
        }
        sqlSession.close();
    }
}

foreach标签

用于循环java中的数组和list集合的。主要用于在sql的in语句中。

参数为非对象形式

dao接口文件

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.ArrayList;
import java.util.List;

public interface TestDao {
    
    public List<Test> selectInt(ArrayList<String> arrayList);
}

sql映射文件

<select id="selectInt" resultType="org.lowell.mybatis.Test">
    select * from test where name in
    <!--
        collection:表示接口中方法参数的类型。如果是数组使用array,如果是list集合使用list
        item:自定义的,表示数组和集合的成员的变量
        open:循环开始时的字符
        close:循环结束时的字符
        separator:集合成员之间的分隔符
        -->
    <foreach collection="list" item="myName" open="(" close=")" separator=",">
        #{myName}
    </foreach>
</select>

java执行程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("lowell");
        arrayList.add("xxx");
        arrayList.add("liuweida");
        List<Test> tests = dao.selectInt(arrayList);
        for (Test test1 : tests) {
            System.out.println("-----------" + test1 + "----------");
        }
        sqlSession.close();
    }
}

参数为对象

dao接口文件

package org.lowell.dao;

import org.lowell.mybatis.Test;

import java.util.ArrayList;
import java.util.List;

public interface TestDao {
    
    public List<Test> selectInt(ArrayList<Test> arrayList);
}

sql映射文件

<select id="selectInt" resultType="org.lowell.mybatis.Test">
    select * from test where name in
    <!--
        collection:表示接口中方法参数的类型。如果是数组使用array,如果是list集合使用list
        item:自定义的,表示数组和集合的成员的变量
        open:循环开始时的字符
        close:循环结束时的字符
        separator:集合成员之间的分隔符
        -->
    <foreach collection="list" item="myName" open="(" close=")" separator=",">
        #{myName.name}
    </foreach>
</select>

java执行程序

package org.lowell;

import org.apache.ibatis.session.SqlSession;
import org.lowell.dao.TestDao;
import org.lowell.mybatis.Test;
import org.lowell.utils.MyBatisUtils;

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

public class MyApp {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        // 使用mybatis的动态代理
        TestDao dao = sqlSession.getMapper(TestDao.class);
        ArrayList<Test> arrayList = new ArrayList<>();
        Test test = new Test();
        test.setName("lowell");
        arrayList.add(test);
        test = new Test();
        test.setName("xxx");
        arrayList.add(test);
        List<Test> tests = dao.selectInt(arrayList);
        for (Test test1 : tests) {
            System.out.println("-----------" + test1 + "----------");
        }
        sqlSession.close();
    }
}

动态sql代码片段

<sql></sql>标签用于定义SQL片段,以便其他SQL标签可以复用。

  1. 定义代码片段

    <sql id="自定义名称(唯一)">
    	// sql语句,表名,字段等。
    </sql>
    
  2. 使用代码片段

    <include refid="定义时自定义名称(唯一)"/>
    

示例:

<?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="org.lowell.dao.TestDao">

    <!--定义sql的片段-->
    <sql id="testSelect">
        select * from test
    </sql>

    <select id="selectInt" resultType="org.lowell.mybatis.Test">
        <include refid="testSelect"/> where name in
        
        <foreach collection="list" item="myName" open="(" close=")" separator=",">
            #{myName.name}
        </foreach>
    </select>
</mapper>

数据库的属性配置文件

把数据库的配置信息单独放到一个文件中,和mybatis主配置文件分开。便于修改保存和处理多个数据库的信息。

  1. 在resources目录中定义一个属性配置文件,xxx.properties,例如:test.properties。在属性配置文件中定义数据的格式是:key=value。key使用.做多级分隔。

    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8
    jdbc.username=root
    jdbc.password=root
    
  2. 在mybatis主配置文件中,使用<property>指定文件的位置。

    <?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" />
    
        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
    
        <typeAliases>
            <package name="org.lowell.mybatis"/>
        </typeAliases>
        <environments default="dev">
            <environment id="dev">
                <transactionManager type="JDBC"/>
                <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>
        <mappers>
            <!--sql映射文件的位置,一个mapper标签指定一个文件的位置,一般来说就是一个表-->
            <mapper resource="org\lowell\dao\TestDao.xml"/>
        </mappers>
    </configuration>
    

指定多个mapper文件

第一种方式

<mappers>
    <!--sql映射文件的位置,一个mapper标签指定一个文件的位置,一般来说就是一个表-->
    <mapper resource="org\lowell\dao\TestDao.xml"/>
    <mapper resource="org\lowell\dao\StudentDao.xml"/>
</mappers>

第二种方式

<mappers>
    <!--
        name:xml文件,sql映射文件所在的包名,这个包中所有xml文件一次性都加载给mybatis
        使用package的条件:
         1. mapper名称需要和接口名称一致,区分大小写
         2. mapper文件和dao接口需要在同一目录
        -->
    <package name="org.lowell.dao"/>
</mappers>

PageHelper

PageHelper用于做数据分页。

  1. 先在pom.xml配置PageHelper的依赖

    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.2.0</version>
    </dependency>
    
  2. 加入plugin,在mybatis的主配置文件中。

    <environments default="dev">之前加入

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
    
  3. dao接口

    package org.lowell.dao;
    
    import org.lowell.mybatis.Test;
    
    import java.util.List;
    
    public interface TestDao {
    
        public List<Test> selectAll();
    }
    
  4. sql映射文件

    <select id="selectAll" resultType="org.lowell.mybatis.Test">
        select * from test order by id
    </select>
    
  5. java执行文件

    package org.lowell;
    
    import com.github.pagehelper.PageHelper;
    import org.apache.ibatis.session.SqlSession;
    import org.lowell.dao.TestDao;
    import org.lowell.mybatis.Test;
    import org.lowell.utils.MyBatisUtils;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MyApp {
        public static void main(String[] args) throws IOException {
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
            // 使用mybatis的动态代理
            TestDao dao = sqlSession.getMapper(TestDao.class);
            // 加入分页
            // pageNum:从多少页开始
            // pageSize:一页有多少数据
            PageHelper.startPage(1,3);
            List<Test> tests = dao.selectAll();
            for (Test test1 : tests) {
                System.out.println("-----------" + test1 + "----------");
            }
            sqlSession.close();
        }
    }
    

配置日志功能

Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK logging

MyBatis 内置日志工厂会基于运行时检测信息选择日志委托实现。它会(按上面罗列的顺序)使用第一个查找到的实现。当没有找到这些实现时,将会禁用日志功能。

不少应用服务器(如 Tomcat 和 WebShpere)的类路径中已经包含 Commons Logging。注意,在这种配置环境下,MyBatis 会把 Commons Logging 作为日志工具。这就意味着在诸如 WebSphere 的环境中,由于提供了 Commons Logging 的私有实现,你的 Log4J 配置将被忽略。这个时候你就会感觉很郁闷:看起来 MyBatis 将你的 Log4J 配置忽略掉了(其实是因为在这种配置环境下,MyBatis 使用了 Commons Logging 作为日志实现)。如果你的应用部署在一个类路径已经包含 Commons Logging 的环境中,而你又想使用其它日志实现,你可以通过在 MyBatis 配置文件 mybatis-config.xml 里面添加一项 setting 来选择其它日志实现。

<configuration>
  <settings>
    <setting name="logImpl" value="LOG4J"/>
  </settings>
</configuration>

可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING,或者是实现了 org.apache.ibatis.logging.Log 接口,且构造方法以字符串为参数的类完全限定名。

你也可以调用以下任一方法来选择日志实现:

org.apache.ibatis.logging.LogFactory.useSlf4jLogging();
org.apache.ibatis.logging.LogFactory.useLog4JLogging();
org.apache.ibatis.logging.LogFactory.useJdkLogging();
org.apache.ibatis.logging.LogFactory.useCommonsLogging();
org.apache.ibatis.logging.LogFactory.useStdOutLogging();

应该在调用其它 MyBatis 方法之前调用以上的某个方法。另外,仅当运行时类路径中存在该日志实现时,日志实现的切换才会生效。如果你的环境中并不存在 Log4J,你却试图调用了相应的方法,MyBatis 就会忽略这一切换请求,并将以默认的查找顺序决定使用的日志实现。

关于 SLF4J、Apache Commons Logging、Apache Log4J 和 JDK Logging 的 API 介绍不在本文档介绍范围内。不过,下面的例子可以作为一个快速入门。有关这些日志框架的更多信息,可以参考以下链接:

日志配置

你可以通过在包、映射类的全限定名、命名空间或全限定语句名上开启日志功能,来查看 MyBatis 的日志语句。

再次提醒,具体配置步骤取决于日志实现。接下来我们会以 Log4J 作为示范。配置日志功能非常简单:添加一个或多个配置文件(如 log4j.properties),有时还需要添加 jar 包(如 log4j.jar)。下面的例子将使用 Log4J 来配置完整的日志服务。一共两个步骤:

步骤 1:添加 Log4J 的 jar 包

由于我们使用的是 Log4J,我们要确保它的 jar 包可以被应用使用。为此,需要将 jar 包添加到应用的类路径中。Log4J 的 jar 包可以在上面的链接中下载。

对于 web 应用或企业级应用,你可以将 log4j.jar 添加到 WEB-INF/lib 目录下;对于独立应用,可以将它添加到 JVM 的 -classpath 启动参数中。

步骤 2:配置 Log4J

配置 Log4J 比较简单。假设你需要记录这个映射器的日志:

package org.mybatis.example;
public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

在应用的类路径中创建一个名为 log4j.properties 的文件,文件的具体内容如下:

# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

上述配置将使 Log4J 详细打印 org.mybatis.example.BlogMapper 的日志,对于应用的其它部分,只打印错误信息。

为了实现更细粒度的日志输出,你也可以只打印特定语句的日志。以下配置将只打印语句 selectBlog 的日志:

log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE

或者,你也可以打印一组映射器的日志,只需要打开映射器所在的包的日志功能即可:

log4j.logger.org.mybatis.example=TRACE

某些查询可能会返回庞大的结果集。这时,你可能只想查看 SQL 语句,而忽略返回的结果集。为此,SQL 语句将会在 DEBUG 日志级别下记录(JDK 日志则为 FINE)。返回的结果集则会在 TRACE 日志级别下记录(JDK 日志则为 FINER)。因此,只要将日志级别调整为 DEBUG 即可:

log4j.logger.org.mybatis.example=DEBUG

但如果你要为下面的映射器 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="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

这时,你可以通过打开命名空间的日志功能来对整个 XML 记录日志:

log4j.logger.org.mybatis.example.BlogMapper=TRACE

而要记录具体语句的日志,可以这样做:

log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE

你应该会发现,为映射器和 XML 文件打开日志功能的语句毫无差别。

posted @ 2020-09-22 22:29  Lowell  阅读(103)  评论(0)    收藏  举报