目录
框架:就是技术的封装
1.mybatis是什么?
原来是apache的一个开源项目,叫ibatis
2010年转移谷歌 从3.0开始 改名为mybatis
mybatis是一款优秀的持久层框架
servlet(负责接收前端请求 调用其他的java程序处理 响应) web层
service(业务逻辑层) 验证数据 调用dao 结果 组装 服务层(逻辑处理,数据组装)
dao(data access Object) jdbc 数据持久层
mybatis是对jbdc的轻量级的封装,提供一些自己定义的类和接口来实现功能,提供专门xml文件来进行配置,以及可以自动的对查询结果进行封装,是一个是一个orm(ORM Object Relational Mapping 对象关系映射)实现,支持动态的sql,以及数据缓存。
2.mybatis的搭建
- 创建一个maven项目,在pom.xml文件中添加mybatis,mysql依赖的jar
- 创建一个数据库表,以及一个对应的Java模型类
mybatis
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
mysql
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!--添加mybatis,mysql依赖的jar-->
CREATE DATABASE ssm_db CHARSET utf8
CREATE TABLE admin(
id INT PRIMARY KEY AUTO_INCREMENT,
account VARCHAR(20),
PASSWORD VARCHAR(50)
)
3.创建 MyBatis 全局配置文件
在resource文件下新建mybatis.xml文件,同时配置文件
<?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">
<!--对xml文件的约束,可以配一些什么文件-->
<configuration>
<!--
配置连接数据库相关的配置
-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/><!-- 事务管理类型-->
<dataSource type="POOLED"><!-- 配置数据源,type="POOLED",是否使用数据库连接-->
<property name="driver" value="com.mysql.cj.jdbc.Driver" /><!--驱动类-->
<property name="url" value="jdbc:mysql://127.0.0.1:3306/ssm_db?serverTimezone=Asia/Shanghai" />
<property name="username" value="root" />
<property name="password" value="cdd"/>
</dataSource>
</environment>
</environments>
</configuration>
4.创建 sql 映射文件
在resource文件下新建mappers文件,创建AdminMapper.xml文件,配置数据库连接信息,配置sql映射文件
<?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">
<!--sql映射文件,把所有sql语句分离到xml文件中-->
<mapper namespace="com.ffyc.mybatis.dao.AdminDao">
<select id="findAdminById" resultType="com.ffyc.mybatis.model.Admin" parameterType="int">
select * from admin where id =#{id}
</select>
<!-- select*从后端接收到的数据会封装到Admin中去,在传到接口中去-->
<!-- resultType是返回值的类型,paramaterType是参数的类型,id与方法名一样,namespace与接口地址一样-->
<!-- 定义 sql 语句 有多个标签可以使用-->
</mapper>
5.创建sql映射文件
定义一个与接口方法名一样的查询语句
<mappers>
<mapper resource="mappers/AdminMapper.xml"></mapper>
</mappers>
6.创建一个访问接口
定义一个方法,方法名与sql的映射文件中的id一致
public interface AdminDao {
public Admin findAdminById(int id);
}
7.测试mybatis
新建一个类来测试
package com.ffyc.mybatis.test;
import com.ffyc.mybatis.dao.AdminDao;
import com.ffyc.mybatis.model.Admin;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
public class testAdmin {
public static void main(String[] args) throws IOException {
// 读取mybatis核心配置文件
Reader reader = Resources.getResourceAsReader("mybatis.xml");
// 创建sqlSessionFactory
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
// 创建sqlSession,session会话,一次与数据可交互,和之前的connection相似
SqlSession sqlSession= sessionFactory.openSession();
// 创建访问接口的代理对象,活动接口的class文件的class对象
AdminDao adminDao= sqlSession.getMapper(AdminDao.class);
// 使用代理对象访问接口中对应的方法,本质上调用的是接口对应的sql映射文件中的sql
Admin admin= adminDao.findAdminById(1);
System.out.println(admin);
// 关闭与数据库连接的会话对象
sqlSession.close();
}
}
测试成功,成功从数据库获取到数据
8.数据源(datasource)
jdbc是自动事务提交,不用自己提交,事务提交后数据就保存到了数据库
数据库事务,是对一次数据库操作过程中的多条sql进行管理控制,保证一次执行中的sql语句作为一个整体,要么一起成功,要么一起失败。
9.数据库连接池(缓冲池)
现在每与数据库交互一次,创建一个数据库连接对象(connection,SqlSession),用完就销毁关闭,下一次需要,重复这个过程,问题:频繁创建销毁对象,需要开销
池的概念:
数据库连接池思想:可以在启动时设置一个容器,在里面初始化好一些数据库连接对象,有请求到来时,可以不用每次创建销毁,可以重复使用,减少了频繁创建销毁连接对象的开销
一般设置:
- 初始链接对象的数量
- 最大连接的数量
- 最大等待时间
<!-- 导入属性文件,是一个键值对,主要用来存放项目中配置文件的-->
<properties resource="config.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/><!-- 事务管理类型-->
<dataSource type="POOLED"><!-- 配置数据源,type="POOLED",是否使用数据库连接-->
<property name="driver" value="${driverName}" /><!--驱动类-->
<property name="url" value="${url}" />
<property name="username" value="${uname}" />
<property name="password" value="${upassword}"/>
</dataSource>
</environment>
</environments>
driverName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssm_db?serverTimezone=Asia/Shanghai
uname=root
upassword=cdd
两个文件中的键值对相对应
运行顺利
<!-- 配置类型别名-->
<typeAliases>
<!-- <typeAlias type="com.ffyc.mybatis.model.Admin" alias="Admin"></typeAlias>-->
<package name="com.ffyc.mybatis.model"/>
</typeAliases>
<select id="findAdminById" resultType="Admin" parameterType="int">
select * from admin where id =#{id}
</select>
打印日志
<!-- mybatis文件设置-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
使用$报错
10.增
keyColumn数据库列名 useGeneratedKeys京适用于insert,update,true就会取出数据库生成的主键 keyProperty="id"指定主键对应的属性
//只传递两个参数
void saveAdmin(@Param("acc") String account,@Param("pwd") String password);
//使用一个对象传递一堆参数
void saveAdmin1(Admin admin);
<insert id="saveAdmin">
insert into admin (account,password) value(#{acc},#{pwd})
</insert>
<insert id="saveAdmin1" parameterType="Admin" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into admin (account,password) value(${account},${password})
</insert>
#、$的使用区别
-
#{} 占位符,是经过预编译的,编译好 SQL 语句再取值,#方式能够防止 sql 注入 #{}:select * from t_user where uid=#{uid} ${} 拼接符,会传入参数字符串,取值以后再去编译 SQL 语句,$方式无法防止 Sql 注入 ${} ${}:select * from t_user where uid= '1' 注意:MyBatis 排序时使用 order by 动态参数时需要注意,用$而不是#
AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
String account = "tom";
String password="123";
Admin admin=new Admin();
admin.setAccount(account);
admin.setPassword(password);
//使用一个对象,传递多个参数
adminDao.saveAdmin1(admin);
//传进两个数据
adminDao.saveAdmin("jim","222");
11.删
void deleteAdmin(int id);
<delete id="deleteAdmin" parameterType="int">
delete from admin where id = #{id}
</delete>
删除数据库id为10的数据
adminDao.deleteAdmin(10);
12.改
void updateAdmin(Admin admin);
<update id="updateAdmin" parameterType="admin">
update admin set account = #{account},password=#{password} where id=#{id}
</update>
adminDao.saveAdmin("jim","222");
adminDao.updateAdmin(admin);
13.查
先在接口中定义方法名,方法类型和返回值类型
/*
* 接口中的方法名与xml文件中的id一致
* 接口中的方法类型与xml中的标签中的parameterType类型相同
* 接口中的返回值类型与xml中的标签中的resultType类型相同*/
Admin findAdminById(int id);
在AdminMapper.xml文件中配置
<!-- 使用代理对象-->
<select id="findAdminById" resultType="Admin" parameterType="int">
select * from admin where id =#{id}
</select>
在方法中使用,运行
public class testAdmin1 {
public static void main(String[] args) {
SqlSession sqlSession= MybatisUtil.getSqlSession();
AdminDao adminDao=sqlSession.getMapper(AdminDao.class);
adminDao.findAdminById(3);
sqlSession.close();
}
}
查出数据库中id为3的数据
14.对象映射
如果表中的类名与类中的属性名完全相同,mybatis会自动将查询结果封装 到POJO对象中. 如果java中使用标准驼峰命名,数据库中使用下划线连接命名,可以开始全局 设置实现自动转换
在mybatis.xml文件中添加
<setting name="mapUnderscoreToCamelCase" value="true"/>
<select id="findAdminById" resultType="Admin" parameterType="int">
select id,account,password,admin_gender from admin where id =#{id}
</select>
此时可以实现转换
15.返回简单基本类型
<select id="findAdminCount" resultType="int">
select count (*) from admin
</select>
计数
List<Admin> findAdmins();
<select id="findAdmins" resultType="Admin">
select * from admin
</select>
输出数据库中的信息
16.特殊处理定义ResultMap
<!-- 在特殊轻快下,我们可以自己进行手动映射 resultMap mapping,映射
id=唯一的标识
type=最终要返回的类型
在特殊情况下自己来映射
property属性名
-->
<resultMap id="adminMap" type="Admin">
<result column="gender" property="adminGender"></result>
</resultMap>
<select id="findAdmins1" resultMap="adminMap">
select id,account,password,admin_gender as gender from admin
</select>
特殊情况下的映射
mybatis的日志功能
<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
17.多表关联嵌套
<!-- 把学生关联的宿舍和操作人信息分别封装到宿舍对象和管理员对象中去,属于嵌套映射
typeStudent中的dorm映射到Dorm中去,dnum(sql中的)列为num(Student的dorm中的)
admin映射到Admin
-->
<association property="dorm" javaType="Dorm">
<result column="dnum" property="num"></result>
</association>
<association property="admin" javaType="Admin">
<result column="account" property="account"></result>
</association>
</resultMap>
<select id="findStudentById" resultMap="studentmap" parameterType="int">
SELECT s.id,
s.num,
s.name,
s.gender,
d.num dnum,
a.account
FROM student s
LEFT JOIN dorm d ON s.dormid=d.id
LEFT JOIN admin a ON s.adminid=a.id
WHERE s.id=#{id}
</select>
查询结果
映射方式
<!--
指定mybatis自动映射的策略
PARTIAL 部分,如果没有嵌套映射,会自动映射结果,一旦使用了嵌套映射,所有都不自动映射,是mybatis默认值
NONE 关闭自动映射,即使是单张表
FULL 无论是否嵌套映射 都会开启自动映射结果
-->
<setting name="autoMappingBehavior" value="PARTIAL"/>
嵌套查询:
<!-- 嵌套查询,把一次查询分为多次-->
<resultMap id="studentMap1" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<association property="dorm" javaType="Dorm" select="findDormById" column="dormid"></association>
<association property="admin" javaType="Admin" select="findAdminById" column="adminid"></association>
</resultMap>
<select id="findStudentById1" resultType="Student" resultMap="studentMap1" parameterType="int">
select id,num,name,gender,dormid,adminid from student where id=#{id}
</select>
<select id="findDormById" parameterType="int" resultType="Dorm">
select num from dorm where id=#{dormid}
</select>
<select id="findAdminById" parameterType="int" resultType="Admin">
select account from admin where id=#{adminid}
</select>
查询结果
18.常用注解标签
@Delete("delete from student where id=#{id}"}
@Results(id="stumap",value={
@Result(id=true,column="id",property="id"),
@Result(column="num",property="num")})
@Insert ("insert into student(num,name,gender)value(#{},#{},#{})))")
@Insert : 插入 sql , 和 xml insert sql 语法完全一样
@Select : 查询 sql, 和 xml select sql 语法完全一样
@Update : 更新 sql, 和 xml update sql 语法完全一样
@Delete : 删除 sql, 和 xml delete sql 语法完全一样
@Param : 入参
@Results : 设置结果集合
@Result : 结果
注解单张表使用比较方便,多张表不建议使用
支持动态sql以及数据缓存
单元测试
/*
* 单元测试,只执行某一个方法
* */
@Test public void find(){
System.out.println("find");
}
MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。 如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么 的痛苦,确保不能忘了空格或在列表的最后省略逗号。动态 SQL 可以彻底处理 这种痛苦
添加jar包
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>provided</scope>
</dependency>
if条件判断
where 动态根据where标签内的if是否成立,动态添加where关键字,还可以去除条件前面的and或者or
<select id="findStudent" resultType="Student" parameterType="Student">
select id,num,name,gender from student
<where>
<if test="num!=0">
num=#{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</where>
</select>
trim标签,有条件成立时,添加指定的关键字 prefixOverrides=“and”覆盖指定的关键字,and
<select id="findStudent" resultType="Student" parameterType="Student">
select id,num,name,gender from student
<trim prefix="where" prefixOverrides="and">
<if test="num!=0">
num=#{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="gender!=null">
or gender=#{gender}
</if>
</trim>
</select>
choose、when、otherwise
<select id="findStudent" resultType="Student" parameterType="Student">
select id,num,name,gender from student
<trim prefix="where" prefixOverrides="and">
<choose>
<when test="num!=0">
num=#{num}
</when>
<when test="name!=0">
and name=#{name}
</when>
<otherwise>
and gender="男"
</otherwise>
</choose>
</trim>
</select>
set可以动态根据是否有条件成立添加set,可以去除最后的逗号
特殊符号
在 mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<>
等,正常书写 mybatis 会报错,需要对这些符号进行转义。具体转义如下所示:
特殊字符 转义字符
< <
> >
" "
’ '
& &
由于xml属于标记语言,类似的符号不能在sql中使用,需要转义符号来代替,或者使用标签<![CDATA[]]>来包裹特殊字符
一级缓存
手机上的缓存,加载图片,先存在手机本地
浏览器中的缓存 访问网页,将一些信息缓存到本地
买票/抢购缓存 多人访问-->数据缓存-->数据库
缓存作用:为了让程序更快的访问到数据,同时也是为了减少数据库的访问压力,可以将数据缓存到内存,客户端的硬盘中
mybatis提供一级缓存和二级缓存,默认开启一级缓存,一级是sqlSession级别的,将查询到的结果缓存到sqlsession对象中,在同一个sqlsession中执行相同的第二次查询时,直接从sqlsessio中拿,
一级缓存失效:sqlsession.close();销毁sqlsession对象
sqlsession.clearCache();清除缓存数据
二级缓存
配置二级缓存配置:
- 启动二级缓存:
在 SqlMapperConfig.xml 中启用二级缓存,如下代码所示,当
cacheEnabled 设置为 true 时启用二级缓存,设置为 false 时禁用二级缓存。
<setting name="cacheEnabled" value="true"/>
- 对象序列化
将所有的 POJO 类实现序列化接口 Java.io. Serializable,导入接口。
- 配置映射文件
在 Mapper 映射文件中添加<cache />,表示此 mapper 开启二级缓存。
当 SqlSeesion 关闭时,会将数据存入到二级缓存.存储机制
<cache flushInterval="1000"></cache>
mybatis二级缓存是sqlsessionFactory级别的,将查询到的数据如果放到二级韩村中,就可以实现多个sqlsession 共享,当第一次查询到数据,关闭sqlsession时将数据存入到耳机缓存中