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&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" 转载请保留原文链接及作者。