01. 上下文配置
MyBatis 上下文配置
-
SqlSessionFactoryBuilder: SqlSessionFactoryBuilder 可被重用创建多个SqlSessionFactory 实例,建议仅将其保存为局部方法变量。 -
SqlSessionFactory: SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,在应用运行期间不要重复创建多次 -
SqlSession: SqlSession 的实例不是线程安全的,因此每个线程都应该有它自己的SqlSession 实例;绝对不能将SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将SqlSession 实例的引用放在任何类型的管理范围中,比如Serlvet 架构中的HttpSession 。如果你现在正在使用一种Web 框架,要考虑SqlSession 放在一个和HTTP 请求对象相似的范围中。 -
映射器实例
(Mapper Instances): 映射器是创建用来绑定映射语句的接口,映射器接口的实例是从SqlSession 中获得的。映射器实例的最佳范围是方法范围,也就是说,映射器实例应该在调用它们的方法中被请求,用过之后即可废弃。并不需要显式地关闭映射器实例,尽管在整个请求范围(Request Scope) 保持映射器实例也不会有什么问题,但是很快你会发现,像SqlSession 一样,在这个范围上管理太多的资源的话会难于控制。
SqlSessionFactory
手工创建SqlSessionFactory
每个基于
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
<?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>
<setting name="cacheEnabled" value="true"/>
<setting name="defaultStatementTimeout" value="3000"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
</settings>
<!-- Continue going here -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://<your_db_host>:<your_db_port>/<your_db_name>"/>
<property name="username" value="<your_db_username>"/>
<property name="password" value="<your_db_password>"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
我们也可以直接从
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
有了
SqlSession session = sqlSessionFactory.openSession();
// 直接使用 SQL 语句
try {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
session.close();
}
// 或者使用 Mapper
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
<?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>
或者直接在接口上添加注解并使用:
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}
SqlSession
每次收到的
下面的示例就展示了这个实践:
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
// do work
} finally {
session.close();
}
在你的所有的代码中一致性地使用这种模式来保证所有数据库资源都能被正确地关闭。
Spring Boot 中集成使用
在 SPRING INITIALIZR 可以直接创建包含org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2
依赖,然后在
// 自定义 Mapper
@SpringBootApplication(scanBasePackages = "wx")
@MapperScan(basePackages = "wx")
@Slf4j
public class Application {}
@Mapper
public interface UserMapper {}
然后我们可以在
# application.properties
mybatis.config-location=classpath:/mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.domain.model
mybatis.type-handlers-package=com.example.typehandler
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=30
然后在
public class City implements Serializable {
...
}
与基于注解的
@Mapper
public interface CityMapper {
@Select("SELECT id, name, state, country FROM city WHERE state = #{state}")
City findByState(String state);
}
在使用的地方直接注入该
@Autowired
CityMapper cityMapper;
this.cityMapper.findByState("CA");
多数据源切换
缓存
<cache
<!--可选参数 -->
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
值得一提的是,缓存只作用于
默认情况下,语句会这样来配置:
<!-- 将 useCache 设置为 false 以忽略某条语句的缓存 -->
<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>
其意味着,映射语句文件中的所有flushCache=true
的
自定义缓存
我们可以添加自定义的缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为。
<cache type="com.domain.something.MyCustomCache"/>
public interface Cache {
String getId();
int getSize();
void putObject(Object key, Object value);
Object getObject(Object key);
boolean hasKey(Object key);
Object removeObject(Object key);
void clear();
}
日志
在
<configuration>
<settings>
...
<setting name="logImpl" value="LOG4J"/>
...
</settings>
</configuration>
这里以
package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}
那么在
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=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
添加以上配置后,org.mybatis.example.BlogMapper
的详细执行操作,且仅记录应用中其它类的错误信息(若有
log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE