MyBatis 01-入门

https://mybatis.org/mybatis-3/zh/getting-started.html
http://www.broadview.com.cn/book/3643

引用 jar 包

可在 https://github.com/mybatis/mybatis-3/releases 下载

或者使用 Maven 来构建项目

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>

从 XML 中构建 SqlSessionFactory

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

<?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>
    <settings>
        <!-- logImpl 属性配置指定使用 LOG4J 输出日志 -->
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <typeAliases>
        <!-- 配置了一个包的别名,如:com.bin.model.Country,在使用类时可以使用 Country 即可,或采用如下方式 -->
        <!-- <typeAlias alias="Country" type="com.bin.model.Country"/> -->
        <package name="com.bin.model"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <!-- 配置数据库连接  -->
            <transactionManager type="JDBC"/>
            <dataSource type="UNPOOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!-- MyBatis 的 SQL 语句和映射配置文件 -->
        <mapper resource="com/bin/mapper/CountryMapper.xml"/>
    </mappers>
</configuration>

MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,可使从 classpath 或其他位置加载资源文件更加容易。

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

不使用 XML 构建 SqlSessionFactory

如果你更愿意直接从 Java 代码而不是 XML 文件中创建配置,或者想要创建你自己的配置构建器,MyBatis 也提供了完整的配置类,提供所有和 XML 文件相同功能的配置项。

// https://stackoverflow.com/questions/22517318/cant-find-some-mybatis-classes-to-import-in-getting-started-guide/42051489#42051489
public interface CountryMapper {
    @Select("select id, countryname, countrycode from country")  // xml 示例中这行注释
    public List<Country> selectAll();
}

class MyDataSourceFactory implements DataSourceFactory {
    private Properties prop;

    @Override
    public DataSource getDataSource() {
        PooledDataSource ds = new PooledDataSource();
        ds.setDriver(prop.getProperty("driver"));
        ds.setUrl(prop.getProperty("url"));
        ds.setUsername(prop.getProperty("user"));
        ds.setPassword(prop.getProperty("password"));
        return ds;
    }

    @Override
    public void setProperties(Properties prprts) {
        prop = prprts;
    }
}

public class MyBatisJavaConfClient {

    private static SqlSessionFactory sesFact = null;

    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        prop.setProperty("driver", "com.mysql.cj.jdbc.Driver");
        prop.setProperty("url", "jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&characterEncoding=utf8");
        prop.setProperty("user", "root");
        prop.setProperty("password", "root");

        MyDataSourceFactory mdsf = new MyDataSourceFactory();
        mdsf.setProperties(prop);
        DataSource ds = mdsf.getDataSource();

        TransactionFactory trFact = new JdbcTransactionFactory();
        Environment environment = new Environment("development", trFact, ds);
        Configuration configuration = new Configuration(environment);
        configuration.addMapper(CountryMapper.class);

        sesFact = new SqlSessionFactoryBuilder().build(configuration);
        try (SqlSession session = sesFact.openSession()) {
            List<Country> countryList = session.selectList("selectAll");
            System.out.println(countryList);
        }

    }
}

注意该例中,configuration 添加了一个映射器类(mapper class)。映射器类是 Java 类,它们包含 SQL 映射语句的注解从而避免依赖 XML 文件。不过,由于 Java 注解的一些限制以及某些 MyBatis 映射的复杂性,要使用大多数高级映射(比如:嵌套联合映射),仍然需要使用 XML 配置。有鉴于此,如果存在一个同名 XML 配置文件,MyBatis 会自动查找并加载它(在这个例子中,基于类路径和 CountryMapper.class 的类名,会加载 CountryMapper.xml)。

从 SqlSessionFactory 中获取 SqlSession

既然有了 SqlSessionFactory,顾名思义,我们就可以从中获得 SqlSession 的实例了。SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:

try (SqlSession session = sqlSessionFactory.openSession()) {
    List<Country> countryList = sqlSession.selectList("selectAll");
}

诚然,这种方式能够正常工作,并且对于使用旧版本 MyBatis 的用户来说也比较熟悉。不过现在有了一种更简洁的方式 ——使用正确描述每个语句的参数和返回值的接口(比如 BlogMapper.class),你现在不仅可以执行更清晰和类型安全的代码,而且还不用担心易错的字符串字面值以及强制类型转换。

例如:

try (SqlSession session = sqlSessionFactory.openSession()) {
    CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
    List<Country> countryList = mapper.selectAll();
}

CountryMapper.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="com.bin.mapper.CountryMapper">
    <!-- 不能和 接口中的注解同时使用 -->
    <select id="selectAll" resultType="Country">
        select id, countryname, countrycode from country
    </select>
</mapper>

命名空间的作用有两个,一个是利用更长的完全限定名来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定。就算你觉得暂时用不到接口绑定,你也应该遵循这里的规定,以防哪天你改变了主意。 长远来看,只要将命名空间置于合适的 Java 包命名空间之中,你的代码会变得更加整洁,也有利于你更方便地使用 MyBatis。

作用域(Scope)和生命周期

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域中。 换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。 这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。 下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession session = sqlSessionFactory.openSession()) {
  // 你的应用逻辑代码
}

在你的所有的代码中一致地使用这种模式来保证所有数据库资源都能被正确地关闭。

映射器实例

映射器是一些由你创建的、绑定你映射的语句的接口。映射器接口的实例是从 SqlSession 中获得的。因此从技术层面讲,任何映射器实例的最大作用域是和请求它们的 SqlSession 相同的。尽管如此,映射器实例的最佳作用域是方法作用域。 也就是说,映射器实例应该在调用它们的方法中被请求,用过之后即可丢弃。 并不需要显式地关闭映射器实例,尽管在整个请求作用域保持映射器实例也不会有什么问题,但是你很快会发现,像 SqlSession 一样,在这个作用域上管理太多的资源的话会难于控制。 为了避免这种复杂性,最好把映射器放在方法作用域内。下面的示例就展示了这个实践:

try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  // 你的应用逻辑代码
}

日志

Mybatis 的内置日志工厂提供日志功能,内置日志工厂将日志交给以下其中一种工具作代理:

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

MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具。它会使用第一个查找得到的工具(按上文列举的顺序查找)。如果一个都未找到,日志功能就会被禁用。

可以通过在 MyBatis 配置文件 mybatis-config.xml 里面添加一项 setting 来选择别的日志工具。

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

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

; Global logging configuration
log4j.rootLogger=ERROR, stdout
; MyBatis logging configuration...
log4j.logger.com.bin.mapper.CountryMapper=TRACE
; 你也可以将日志的记录方式从接口级别切换到语句级别,从而实现更细粒度的控制。如下配置只对 selectAll 语句记录日志:
log4j.logger.com.bin.mapper.CountryMapper.selectAll=TRACE
; 可以对一组映射器接口记录日志,只要对映射器接口所在的包开启日志功能即可:
log4j.logger.com.bin.mapper=TRACE
; 如需对 XML 文件记录日志,只要对命名空间增加日志记录功能即可:
log4j.logger.com.bin.mapper.CountryMapper=TRACE
; Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

MyBatis 日志的最低级别时 TREAC,这个级别下会输出执行 SQL 过程中的详细信息。

EBUG [main] - ==>  Preparing: select id, countryname, countrycode from country
DEBUG [main] - ==> Parameters:
TRACE [main] - <==    Columns: id, countryname, countrycode
TRACE [main] - <==        Row: 1, 中国, CN
TRACE [main] - <==        Row: 2, 美国, US
TRACE [main] - <==        Row: 3, 俄罗斯, RU
TRACE [main] - <==        Row: 4, 英国, GB
TRACE [main] - <==        Row: 5, 法国, FR
DEBUG [main] - <==      Total: 5

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:MyBatis 01-入门

文章字数:2.6k

本文作者:Bin

发布时间:2019-09-18, 23:08:44

最后更新:2019-10-09, 21:18:56

原始链接:http://coolview.github.io/2019/09/18/MyBatis/MyBatis%2001-%E5%85%A5%E9%97%A8/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录