数据源配置
首先需要安装数据库驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
然后再 application.yml 文件中配置数据源. 如果没有安装数据库驱动,那么 Intellij 在 driver-class-name
这一行会有报错提示.
# data source
spring:
datasource:
url: jdbc:mysql://localhost/LearnBatis
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
MyBatis 依赖
mybatis-spring-boot-starter
官方文档: mybatis-spring-boot-autoconfigure – 简介
能够帮我们快速的基于 SpringBoot 构建 MyBaits 应用. 让我们可以编写更少的 XML 配置.
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
MyBatisConfig 类
编写下面的代码时,如果数据源配置相关操作没有完成 Intellij 会提示找不到 DataSource
实例
@Configuration
//@MapperScan("xxxx.xxxx.dao")
class MyBatisConfig {
@Bean
fun sqlSessionFactory(dataSource: DataSource):SqlSessionFactory{
val factoryBean = SqlSessionFactoryBean()
factoryBean.setDataSource(dataSource)
return factoryBean.`object`
?: throw IllegalStateException("SqlSessionFactory creation failed")
}
}
使用 Kotlin 编写时,注意一些 getXX()
方法在 Kotlin 中是不能够直接使用的.
这里还要注意,如果你把一些 Java 代码直接复制到 Kotlin 项目中, 让 Intellij 帮助你自动将其转换为 Kotlin 代码. 可能会出现一些 @Throws
标签. 这些标签是为了在 Kotlin 和 Java 互相调用时发挥作用,纯 Kotlin 项目不需要 @Throws
根据官方文档 mybatis-spring ,可以知道,这里的配置代码主要作用是提供一个 SqlSessionFactory
实例. 后续在各个业务请求中, MyBaits 会通过 SqlSessionFactory
来创建 SqlSession
对数据库进行操作. 各自的作用可以参考 MyBatis 作用域和生命周期1
在 Config 类中配置 Mybatis 时, SqlSessionFactoryBean
对象唯一必须需要设置的属性是: ==DataSource 数据源==
其他常用的配置属性有:
configLocation
: 它用来指定 MyBatis 的 XML 配置文件路径
mapperLocations
指定 MyBatis 的映射器 XML 配置文件的位置。属性的值是一个 Ant 风格的字符串,可以指定加载一个目录中的所有文件,或者从一个目录开始递归搜索所有目录
mapperLocations
当然也可以通过代码来对 映射器 XML 配置文件进行配置. 注意这里是 **getResources ** 而不是 getResource (这地方卡了我两三个小时)
val mapperLocations = "classpath*:mapper/**/*Mapper.xml"
factoryBean.setMapperLocations(
*PathMatchingResourcePatternResolver().getResources(mapperLocations)
)
这里的 *
是 Kotlin 中的展开操作符(spread operator) ,用于将数组展开作为可变数量参数3.
因为 setMapperLocations
中可以接收多个资源
public void setMapperLocations(Resource... mapperLocations)
编写 DAO 和 XML 映射器
@Mapper
interface DiaryTagDAO {
@Select("SELECT TagID,TagName FROM Tags")
fun getTagList():List<DiaryTag>
@Select("SELECT TagID,TagName FROM Tags WHERE TagID=#{id}")
fun getTagById(id:Long):DiaryTag
fun selectTagByName(name:String):DiaryTag
}
这里注意, 如果我们在 DAO 中标注了 @Mapper
标签,那么我就可以不需要在 Config
类添加 @MapperScan
标签
<?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.crowds.learnMybatis.dao.DiaryTagDAO">
<resultMap id="diaryTag" type="com.crowds.learnMybatis.domain.DiaryTag">
<id property="tagID" column="TagID"/>
<result property="tagName" column="TagName"/>
</resultMap>
<select id="selectTagByName" parameterType="String" resultMap="diaryTag">
SELECT Tags.TagID , Tags.TagName FROM Tags
WHERE Tags.TagName = #{name}
</select>
</mapper>
这里需要注意,传入参数使用 #{para}
时,一定不要写成 '#{para}'
把他当成字符串.
测试类
编写一个简单的测试类,测试一下是否运行正常
@SpringBootTest
class DiaryTagServiceImplTest {
@Autowired
private lateinit var diaryTagService: DiaryTagServiceImpl
@Test
fun getTagList() {
val result = diaryTagService.getTagList()
assert(result.size == 1)
}
@Test
fun getTagById() {
val result = diaryTagService.getTagById(1L)
assert( result.tagID == 1L)
}
@Test
fun getTagByName() {
var result = diaryTagService.getTagByName("MyBaits")
println("TagName: ${result.tagName}")
assert(result.tagName == "MyBaits")
}
}
MyBatis 作用域和生命周期
依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。 如果对如何通过依赖注入框架使用 MyBatis 感兴趣,可以研究一下 MyBatis-Spring1 或 MyBatis-Guice 两个子项目
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,创建了 SqlSessionFactory 后就不再需要 SqlSessionFactoryBuilder
因此 SqlSessionFactoryBuilder 实例的最佳作用域是 方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它
以保证所有的 XML 解析资源可以被释放给更重要的事情
SqlSessionFactory
MyBatis 中的 SqlSessionFactory 的生命周期为: ==被创建就应该在应用的运行期间一直存在==
并且没有任何理由丢弃它或重新创建另一个实例
MyBatis 中的 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次
MyBatis 中的 SqlSessionFactory 的最佳作用域是**==应用作用域==**。 有很多方法可以做到,最简单的就是使用**==单例模式==**或者**==静态单例模式==**
SqlSession
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
-
MyBatis 中的 SqlSession 是否是线程安全的,能否被共享
- 不是线程安全的, 所以也不能被共享
MyBatis 中的 SqlSession 的最佳作用域是 ==请求==或==方法==作用域.
因为一个请求或方法刚好就只执行一次 SqlSession
MyBatis 中的 SqlSession 的正确做法是: 每次收到一个请求就==打开一个 SqlSession==,返回响应后,==就关闭 SqlSession==
绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。
如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。
try (SqlSession session = sqlSessionFactory.openSession()) { // 你的应用逻辑代码 }
在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭
映射器实例
映射器是一些绑定映射语句的接口。
映射器接口的实例是从 SqlSession 中获得的。虽然从技术层面上来讲,任何映射器实例的最大作用域与请求它们的 SqlSession 相同。但方法作用域才是映射器实例的最合适的作用域。
也就是说,映射器实例应该在调用它们的方法中被获取,使用完毕之后即可丢弃。 映射器实例并不需要被显式地关闭。
尽管在整个请求作用域保留映射器实例不会有什么问题,但是你很快会发现,在这个作用域上管理太多像 SqlSession 的资源会让你忙不过来。 因此,最好将映射器放在方法作用域内。就像下面的例子一样:
try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class); // 你的应用逻辑代码 }
MyBatis 中的映射器实例应该在==调用它们的方法==中被获取,在使用完毕之后**丢弃**
MyBatis 中的映射器实例应该在调用它们的方法中被获取,在使用完毕之后**==丢弃==**
MyBatis 中的映射器应该被放在**==方法作用域内==** ↩
-
MyBatis-Spring
可变数量参数
可变数量参数1就是就是函数可以接受任意数量的参数, 在 Kotlin 和 Java 中使用不同的方式定义.
↩ ↩// Java void printNumbers(int... numbers) // Kotlin fun printNumbers(vararg numbers: Int)
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于