1、什么是框架?
代码语言:javascript复制它是我们软件开发中的一套解决方案,不同的框架解决的是不同的问题。
使用框架的好处:
框架封装了很多的细节,使开发者可以使用极简的方式实现功能。大大提高开发效率。
2、三层架构
代码语言:javascript复制表现层:
是用于展示数据的
业务层:
是处理业务需求
持久层:
是和数据库交互的
3、持久层技术解决方案
代码语言:javascript复制JDBC技术:
Connection
PreparedStatement
ResultSet
Spring的JdbcTemplate:
Spring中对jdbc的简单封装
Apache的DBUtils:
它和Spring的JdbcTemplate很像,也是对Jdbc的简单封装
以上这些都不是框架
JDBC是规范
Spring的JdbcTemplate和Apache的DBUtils都只是工具类
4.MyBatis
mybatis的概述
代码语言:javascript复制mybatis是一个持久层框架,用java编写的。
它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程
它使用了ORM思想实现了结果集的封装。
mybatis的入门
mybatis的环境搭建
- 第一步:创建maven工程并导入坐标
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.qkongtao</groupId>
<artifactId>MyBatis1</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
- 创建实体类和dao的接口
package dao;
import domain.User;
import java.util.List;
/**
*
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有操作
* @return
*/
List<User> findAll();
}
- 创建Mybatis的主配置文件 SqlMapConifg.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">
<!-- mybatis的主配置文件 -->
<configuration>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
<mappers>
<mapper resource="dao/IUserDao.xml"/>
</mappers>
<!--起别名,可以不用谢写全限定类名-->
<typeAliases>
<typeAlias type="domain.User" alias="user"></typeAlias>
</typeAliases>
</configuration>
- 创建映射配置文件 IUserDao.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">
<mapper namespace="dao.IUserDao">
<!--配置查询所有-->
<select id="findAll" resultType="domain.User">
select * from user
</select>
</mapper>
环境搭建的注意事项:
- 创建IUserDao.xml 和 IUserDao.java时名称是为了和我们之前的知识保持一致。在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper,所以:IUserDao 和 IUserMapper是一样的
- 在idea中创建目录的时候,它和包是不一样的包在创建时:com.itheima.dao它是三级结构目录在创建时:com.itheima.dao是一级目录
- mybatis的映射配置文件位置必须和dao接口的包结构相同
- 映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
- 映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名
mybatis的入门案例
- 读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
- 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
- 创建SqlSession
SqlSession session = factory.openSession();
- 创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
- 执行dao中的方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
- 释放资源
session.close();
in.close();
注意事项: 不要忘记在映射配置中告知mybatis要封装到哪个实体类中 配置的方式:指定实体类的全限定类名
mybatis基于注解的入门案例:
把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL语句,同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。
代码语言:javascript复制package dao;
import domain.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
*
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有操作
* @return
*/
@Select("select * from user")
List<User> findAll();
}
明确: 我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式。不管使用XML还是注解配置。但是Mybatis它是支持写dao实现类的。
MyBatis连接池:
我们在实际开发中都会使用连接池。 因为它可以减少我们获取连接所消耗的时间。
mybatis中的连接池 mybatis连接池提供了3种方式的配置: 配置的位置: 主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。
代码语言:javascript复制 <!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
type属性的取值: 1. POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现 2. UNPOOLED 采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。 3. JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。 注意:如果不是web或者maven的war工程,是不能使用的。我们使用的是tomcat服务器,采用连接池就是dbcp连接池。
MyBatis动态 SQL
- 动态 SQL 之标签我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,如果 username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
<select id="findUserByCondition" resultMap="userMap" resultType="domain.User">
select * from user where 1 =1
<if test="name != null">
and name = #{name}
</if>
<if test="sex != null">
and sex = #{sex}
</if>
</select>
- 动态 SQL 之标签 为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。
<select id="findUserByCondition" resultMap="userMap" resultType="domain.User">
select * from user
<where>
<if test="name != null">
and name = #{name}
</if>
<if test="sex != null">
and sex = #{sex}
</if>
</where>
</select>
- 动态标签之标签 传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)
SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。 * 在 QueryVo 中加入一个 List 集合用于封装参数
代码语言:javascript复制/**
package domain;/*
*Created by tao on 2020-03-26.
*/
import java.util.List;
public class QueryVo {
private User user;
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
- 持久层 Dao 接口
/**
根据QueryVo中的提供的Id集合查询用户信息
*
* @param vo
* @return
*/
List<User> findUserInIds(QueryVo vo);
- 持久层 Dao 映射配置
<!--根据QueryVo中的Id集合查询用户列表-->
<select id="findUserInIds" resultMap="userMap" parameterType="domain.QueryVo">
select * from user
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
foreach SQL语句 * 标签用于遍历集合,它的属性: * collection:代表要遍历的集合元素,注意编写时不要写#{} * open:代表语句的开始部分 * close:代表结束部分 * item:代表遍历集合的每个元素,生成的变量名 * sperator:代表分隔符
MyBatis多表查询
IUserDao配置如下
代码语言:javascript复制<?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="dao.IUserDao">
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
<!--一对一:定义 AccountUser 表的 accountMap-->
<resultMap id="accountMap" type="domain.AccountUser">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用于指定从表方的引用实体属性的 -->
<association property="user" javaType="domain.User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="age" property="age"/>
</association>
</resultMap>
<!--一对多:定义 user 表的 userMap-->
<resultMap id="userMap" type="domain.User">
<!-- 主键字段的对应 -->
<id property="id" column="id"></id>
<!--非主键字段的对应-->
<result property="name" column="name"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="age" column="age"></result>
<!-- collection 是用于建立一对多中集合属性的对应关系ofType 用于指定集合元素的数据类型-->
<collection property="accounts" ofType="domain.Account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
<!--多对多:定义 role 表的 ResultMap-->
<resultMap id="roleMap" type="domain.Role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="domain.User">
<id column="id" property="id"></id>
<result column="username" property="name"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</collection>
</resultMap>
<!-- 一对一查询所有 -->
<select id="findAll" resultMap="accountMap">
select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
</select>
<!--一对多查询所有-->
<select id="findAllDuo" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u left outer join account
a on u.id =a.uid
</select>
<!--一对多查询-->
<select id="findAllDDD" resultMap="roleMap">
select u.*,r.id as rid,r.role_name,r.role_desc from role r left outer join user_role ur on r.id = ur.rid
left outer join user u on u.id = ur.uid;
</select>
</mapper>
- collection: 部分定义了用户关联的账户信息。表示关联查询结果集
- property="accList": 关联查询的结果集存储在 User 对象的上哪个属性。
- ofType="account": 指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。
开启 Mybatis 的延迟加载策略
- 什么是延迟加载 在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
- 什么是立即加载 不管用不用,只要一调用方法,马上发起查询。
- 在对应的四种表关系中:一对多,多对一,一对一,多对多 一对多,多对多:通常情况下我们都是采用延迟加载。 多对一,一对一:通常情况下我们都是采用立即加载。
我们需要在 Mybatis 的配置文件 SqlMapConfig.xml 文件中添加延迟加载的配置。
代码语言:javascript复制<!-- 开启延迟加载的支持 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
Mybatis中的注解开发
要用注解都用注解,要用xml都用xml,不能同时存在,不然会报错
Mybatis 缓存
像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提 高性能。 Mybatis 中缓存分为一级缓存,二级缓存。 1. 什么是缓存 存在于内存中的临时数据。 2. 为什么使用缓存 减少和数据库的交互次数,提高执行效率。 什么样的数据能使用缓存,什么样的数据不能使用 3. 适用于缓存: * 经常查询并且不经常改变的。 * 数据的正确与否对最终结果影响不大的。 4. 不适用于缓存: * 经常改变的数据 * 数据的正确与否对最终结果影响很大的。 * 例如:商品的库存,银行的汇率,股市的牌价。
一级缓存
在不修改数据库的情况下,查询了两次,但最后只执行了一次数据库操作,这就是 Mybatis 提供给我们的一级缓存在起作用了。 **一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。 ** * 手动清空一级缓存 sqlSession.clearCache();//此方法也可以清空缓存
二级缓存:
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。 二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
代码语言:javascript复制<!--配置二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
代码语言:javascript复制<!--开启二级缓存-->
<cache/>
第三步:让当前的操作支持二级缓存(在select标签中配置)
代码语言:javascript复制 <!-- 一对一查询所有 -->
<select id="findAll" resultMap="accountMap" useCache="true">
select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
</select>