1.什么是Mybatis?
自我总结:
Mybatis是Apache的一个开源框架,一开始是ibatis,之后迁移到了Google code上并改名为Mybatis。之后转移到了GitHub。
Mybatis是一个可持久层框架,将Java代码与SQL语句分离,让代码结构更分明,更容易维护。
Mybatis是通过xml和注解的方式进行将(statement、prepraredstatement)进行封装成一个个mapperstatement对象集合,这个对象集合的键值对的键值就是ID。那么你可能会问namespace是什么?为什么namespace不同,ID可以相同;这是为什么呢?
从底层上看:面向接口编程;不需要将DAO层的接口实现,只需将xml与接口绑定,我个人认为底层实现可能是将statement对象作为map的value值,而key则是这个ID值。至于这段代码的解释:
private SqlSession openSession = null;
@Test
public void findMybatis() {
InputStream input = null;
try {
input = Resources.getResourceAsStream("sqlmybatisconfig.xml");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(input);
openSession = build.openSession();
CosMapping mapper = openSession.getMapper(CosMapping.class);//接口不能创建对象 这个通过反射来创建对象 返回值是这个对象 还不是强转 说明内部可能实现的是类模板 返回值按照T类型传输的 并创建对象 但是整体控制在Mybatis哪里管理着,因为我们调用对象的方法内部怎么实现的呢?可能是内部监听器监听到你要请求或者mapper调用时自动跳入到map集合里,并在跳入时传入两个参数(函数名,形参)来匹配当前的map集合 找到ID 并执行statement对象 返回数据封装成Java映射对象。至于为什么namespace不同,ID相同?我猜测两种情况:1.当getmapper时创建map集合 键值对就是(ID和statement)用完就释放或者单利模式;这个只会创建一个map集合,不需要做判断来判定当前需要获取哪一个映射类的class字节码。2.类似于哈希表 一个数组保存各个映射类的class,作为哈希值,链表的key作为ID值,value=statement;我的想法是这样的,具体实现源码暂时没去看。
我个人认为第二个最像了;
List<Cost> findCost = mapper.findCost(1);
System.out.println(findCost);
}
2.Mybatis加载的步骤:
(1)加载配置并初始化
1. 使用何种映射器配置
MyBatis 3之后的SQL语句映射既支持注解也支持XML配置,他们各有优势和缺点,在实例项目中应该如何选择可以参考如下建议:
对于简单语句来说,注解使代码显得更加简洁,然而Java注解对于稍微复杂的语句就会力不从心并且会显得更加混乱。因此,如果你需要做很复杂的事情,那么最好使用XML来映射语句。当然,可以在项目中同时使用基于注解和基于XML配置2种形式的SQL语句映射,MyBatis是支持的。
2. 对象生命周期和作用域
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源释放给更重要的事情。
SqlSessionFactory
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码”坏味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是应用作用域。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。在Spring框架中集成MyBatis时,SqlSessionFactory实例的生命周期由Spring框架管理,不用开发者过多操心。
SqlSession
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此不能被共享,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理作用域中,比如 Servlet 架构中的 HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。下面的示例就是一个确保 SqlSession 关闭的标准模式:
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}
在你的所有代码中一致性地使用这种模式来保证所有数据库资源都能被正确地关闭。
映射器实例(Mapper Instances)
映射器是创建用来绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。因此从技术层面讲,映射器实例的最大作用域是和 SqlSession 相同的,因为它们都是从 SqlSession 里被请求的。尽管如此,映射器实例的最佳作用域是方法作用域。也就是说,映射器实例应该在调用它们的方法中被请求,用过之后即可废弃。并不需要显式地关闭映射器实例,尽管在整个请求作用域(request scope)保持映射器实例也不会有什么问题,但是很快你会发现,像 SqlSession 一样,在这个作用域上管理太多的资源的话会难于控制。所以要保持简单,最好把映射器放在方法作用域(method scope)内。下面的示例就展示了这个实践:
SqlSession session = sqlSessionFactory.openSession();
try {
// 从SqlSession中获取映射器接口实例
BlogMapper mapper = session.getMapper(BlogMapper.class);
// do work
} finally {
session.close();
}
3. #{}和 ${}
${}是链接符 类型是保持原类型,且${value}只能是value 如果传参的是基本数据类型 那么只能是integin和String
#{}是占位符 类型可以是原类型和包装类型 可以一个值封装了多个参数 且#{value}里面的命名随意
#防注入 $不妨;
一般都有# 而$则用在排序名上等。
4.接口+映射文件
规则:
1、映射文件的名称空间一定要和接口的全路径保持一致
2、映射文件中的statementId一定要和接口中的方法名保持一致
3、映射文件的parameterType、resultType一定要和接口中方法的参数类型、返回结果类型保持一致
4、映射文件名称和接口的名称最好保持一致
5、映射文件和接口最好放到一起
6、sqlMapConfig配置文件
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
全局配置文件代码拷贝:
<?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="mysql.properties"></properties> <!-- 配置mybatis运行环境 --> <environments default="cybatis"> <environment id="cybatis"> <!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 --> <transactionManager type="JDBC" /> <!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI --> <!-- POOLED 表示支持JDBC数据源连接池 --> <!-- UNPOOLED 表示不支持数据源连接池 --> <!-- JNDI 表示支持外部数据源连接池 --> <dataSource type="POOLED"> <property name="driver" value="${mysql.driver}" /> <property name="url" value="${mysql.url}" /> <property name="username" value="${mysql.username}" /> <property name="password" value="${mysql.password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="com/yt/dao/Cosmapping.xml"/> </mappers> </configuration>
映射文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> <mapper namespace="com.yt.dao.CosMapping"> <select id="findCost" parameterType="int" resultType="com.yt.domain.Cost"> select * from cost where cost_id=#{id} </select> </mapper>
映射类接口:
package com.yt.dao; import java.util.List; import com.yt.domain.Cost; public interface CosMapping { public List<Cost> findCost(int id); }
测试类:
package com.yt.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.jupiter.api.Test; import com.yt.dao.CosMapping; import com.yt.domain.Cost; import org.apache.ibatis.io.Resources; public class ttest { private SqlSession openSession = null; @Test public void findMybatis() { InputStream input = null; try { input = Resources.getResourceAsStream("sqlmybatisconfig.xml"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } SqlSessionFactory build = new SqlSessionFactoryBuilder().build(input); openSession = build.openSession(); CosMapping mapper = openSession.getMapper(CosMapping.class); List<Cost> findCost = mapper.findCost(1); System.out.println(findCost); } }