版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zpz2411232428/article/details/88676278
Mybatis框架
- MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
- 与数据库打交道,基本替换了JDBC的繁琐编程。
使用步骤(这里只阐述IEDA下maven项目操作mybatis)
- 首先新建maven项目。添加pom文件依赖(主要是这两个依赖)
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
- 添加配置文件 mybatis-config.xml(在resource目录下),用这个配置文件来告诉 mybatis 如何连接数据库
告诉 mybatis 到哪里去找映射关系
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/> //加载驱动
<property name="url" value="${url}"/> //链接地址
<property name="username" value="${username}"/> //用户名
<property name="password" value="${password}"/> //密码
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/> //映射文件的位置
</mappers>
</configuration>
3.提供一映射文件,用来管理 sql 语句,描述 sql 语句与数据库表之间的映射关系
-
因为需要连接数据库,所以我们需要在java这边设置一个对象(student)来接收数据库的数据,对象的属性名最好和数据库表的每列数据名相同,可以避免一些错误。之后从数据库得到的数据就会存在对象里了,我们就可以使用对象操作了。
-
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">
<!-- namespace(命名空间) 用来防止 sql 的命名冲突的 -->
<mapper namespace="mapper.StudentMapper">
<!-- #{Xxx} 用来获取 Student 参数对象中的 Xxx属性-->
<!-- useGeneratedKeys="true" 是告诉 mybatis 要使用由数据库产生的主键值 -->
<!-- keyProperty="主键对应的属性名" -->
<insert id="insert" parameterType="domain.Student"
useGeneratedKeys="true" keyProperty="sid">
insert into student(sid, sname, birthday, sex)
values ( #{sid}, #{sname}, #{birthday}, #{sex})
</insert>
<delete id="delete" parameterType="int">
delete from student where sid = #{sid}
</delete>
<select id="findAll" resultType="domain.Student">
select sid,sname,birthday,sex from student
</select>
<select id="findById" resultType="domain.Student" parameterType="int">
select sid,sname,birthday,sex from student where sid = #{sid}
</select>
<!-- 更新所有列
<update id="update" parameterType="domain.Student">
update student set sname=#{name}, birthday=#{birthday}, sex=#{sex} where sid=#{sid}
</update>
-->
<!-- 动态更新列
Student stu = new Student();
stu.setSid(1001);
stu.setSex("男");
update student set sex=#{sex} where sid=#{sid}
用 set 标签可以去除多余的逗号
-->
<update id="update" parameterType="domain.Student">
update student
<set>
<if test="name != null">
sname=#{sname},
</if>
<if test="birthday != null">
birthday=#{birthday},
</if>
<if test="sex != null">
sex=#{sex},
</if>
</set>
where sid=#{sid}
</update>
<!-- m , n
java.util.Map -> map
java.util.List -> list
java.lang.String -> string
map.put("m", 0);
map.put("n", 5);
-->
<select id="findByPage" parameterType="map" resultType="domain.Student">
select sid,sname,birthday,sex from student limit #{m}, #{n}
</select>
</mapper>
- 接口映射:使用注解的方式,编写sql语句
import domain.Student;
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Map;
public interface StudentMapper {
@Insert("insert into student(sid,sname,birthday,sex) values(#{sid},#{sname}, #{birthday}, #{sex})")
@Options(useGeneratedKeys = true, keyProperty = "sid")
void insert1(Student student);
@Update("update student set sname=#{sname}, birthday=#{birthday}, sex=#{sex} where sid=#{sid}")
void update1(Student student);
@Delete("delete from student where sid=#{sid}")
void delete1(int sid);
@Select("select * from student")
List<Student> findAll1();
@Select("select * from student where sid = #{sid}")
Student findById1(int sid);
@Select("select * from student limit #{m}, #{n}")
List<Student> findByPage1(Map map);
@Select("select * from student where sid = #{sid} and sname = #{sname}")
List<Student> findByMore1(@Param("sid") int sid , @Param("sname") String sname);
}
-xml和接口映射
定义了这样一条规则,当遇到编写简单sql语句时,首先采用接口进行映射,如果遇到接口解决不了的映射,再去使用xml映射
例如:批量删除,这时候注解发挥不了作用
void deleteByIds(List<Integer> list);
<!--多ID删除-->
<delete id="deleteByIds" parameterType="list">
delete from student where sid in
<foreach collection="list" item="l" open="(" close=")" separator=",">
#{l}
</foreach>
</delete>
这样 接口和xml搭配就可以解决很多需求了
- 调用 mybatis api 使用映射文件真正执行增删改查
因为下面代码很多地方重用,所以设成静态共享
1.
static SqlSessionFactory factory; //第一需要一个sqlSessionFactory的工厂类,可以加载mybatis的xml的配置文件,告诉mybatis连接的数据库以及映射的文件
static {
// 读取配置文件
try(InputStream in = Resources.getResourceAsStream("mybatis-config.xml")){ //加载配置文件
// 创建 sqlSession 工厂类
factory = new SqlSessionFactoryBuilder().build(in); //创建一个工厂类
} catch (IOException e) {
e.printStackTrace();
}
}
2.// 创建 sqlSession, 这里的 session 更类似于 jdbc 中的 Connection
SqlSession sqlSession = factory.openSession();
3. 使用sqlsession的各种方法执行对数据库的操作
//xml方式
// 执行新增
Student stu = new Student();
stu.setSname("李五");
stu.setBirthday(new Date());
stu.setSex("男");
// 参数1 : namespace+sql_id , 参数2: 传递sql语句需要的java对象
sqlSession.insert("mapper.StudentMapper.insert", stu );
// 执行 增删改, 没有启用自动提交事务
sqlSession.commit();
System.out.println("sid的值:" + stu.getSid());
// 关闭资源
sqlSession.close();
//接口方式
SqlSession sqlSession = factory.openSession();
// 先通过 sqlSession 获得接口对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student stu = new Student();
stu.setSid(6);
stu.setSname("张鹏展");
stu.setBirthday(new Date());
stu.setSex("男");
// 通过接口对象中声明的方法 执行sql语句
mapper.insert1(stu);
sqlSession.commit();
sqlSession.close();
4.sqlsession的方法很多,这里不在举例,要注意的是,在进行查询时,不需要进行commit操作,其它的对数据有改动的操作都需要commit提交。
复杂sql映射
除了使用 xml mapper 以外,还可以利用 @DeleteProvider @InsertProvider @SelectProvider @UpdateProvider
生成复杂sql
例如:
// 由 @DeleteProvider 注解找到一条sql语句,供 deleteByIds 方法使用
@DeleteProvider(
type = StudentSqlProvider.class,
method = "getDeleteByIdsSql"
)
void deleteByIds(List<Integer> ids);
//手动拼接复杂sql,利用注解传进去
public class StudentSqlProvider {
// 1, 2, 3, list参数名 固定为 list
public static String getDeleteByIdsSql(@Param("list") List<Integer> aaa) {
StringBuilder sb = new StringBuilder(128);
sb.append("delete from student where sid in");
sb.append("(");
for (int i = 0; i < aaa.size(); i++) {
sb.append(aaa.get(i));
if(i < aaa.size()-1) {
sb.append(",");
}
}
sb.append(")");
return sb.toString();
}
}
properties
- 作为configuration 配置下一子标签。可以为一些特定的值配置 例如:
<configuration>
<properties resource="config.properties">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test1?SSH=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</properties>
- 如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:
- 在 properties 元素体内指定的属性首先被读取。
- 然后根据 properties 元素中的 resourc属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
Mybatis几个类的生命周期
- 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 块中以确保每次都能执行关闭。
- 映射器实例(Mapper Instances)
- 映射器是一个你创建来绑定你映射的语句的接口。映射器接口的实例是从 SqlSession 中获得的。因此从技术层面讲,任何映射器实例的最大作用域是和请求它们的 SqlSession 相同的。尽管如此,映射器实例的最佳作用域是方法作用域。也就是说,映射器实例应该在调用它们的方法中被请求,用过之后即可废弃。并不需要显式地关闭映射器实例,尽管在整个请求作用域(request scope)保持映射器实例也不会有什么问题,但是很快你会发现,像 SqlSession 一样,在这个作用域上管理太多的资源的话会难于控制。所以要保持简单,最好把映射器放在方法作用域(method scope)内。
Mabatis 缓存机制
- Mybatis 使用到了两种缓存:本地缓存(local cache)和二级缓存(second level cache)。
- 每当一个新 session 被创建,MyBatis 就会创建一个与之相关联的本地缓存。任何在 session 执行过的查询语句本身都会被保存在本地缓存中,那么,相同的查询语句和相同的参数所产生的更改就不会二度影响数据库了。本地缓存会被增删改、提交事务、关闭事务以及关闭 session 所清空。默认情况下,本地缓存数据可在整个 session 的周期内使用,这一缓存需要被用来解决循环引用错误和加快重复嵌套查询的速度,所以它可以不被禁用掉,但是你可以设置 localCacheScope=STATEMENT 表示缓存仅在语句执行时有效。
- 注意,如果 localCacheScope 被设置为 SESSION,那么 MyBatis 所返回的引用将传递给保存在本地缓存里的相同对象。对返回的对象(例如 list)做出任何更新将会影响本地缓存的内容,进而影响存活在 session 生命周期中的缓存所返回的值。因此,不要对 MyBatis 所返回的对象作出更改,以防后患。