1、什么是框架?
它是我们软件开发中的一套解决方案,不同的框架解决的是不同的问题。 使用框架的好处: 框架封装了很多的细节,使开发者可以使用极简的方式实现功能。大大提高开发效率。
2、三层架构
表现层: 是用于展示数据的 业务层: 是处理业务需求 持久层: 是和数据库交互的
3、持久层技术解决方案
JDBC技术: Connection PreparedStatement ResultSet Spring的JdbcTemplate: Spring中对jdbc的简单封装 Apache的DBUtils: 它和Spring的JdbcTemplate很像,也是对Jdbc的简单封装 以上这些都不是框架 JDBC是规范 Spring的JdbcTemplate和Apache的DBUtils都只是工具类
4.MyBatis
mybatis的概述
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接口的全限定类名。
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属性就是表示采用何种连接池方式。
<!-- 配置数据源(连接池) --> <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 集合用于封装参数
/** 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配置如下
<?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 文件中添加延迟加载的配置。
<!-- 开启延迟加载的支持 --> <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中配置)
<!--配置二级缓存--> <settings> <setting name="cacheEnabled" value="true"/> </settings>
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
<!--开启二级缓存--> <cache/>
第三步:让当前的操作支持二级缓存(在select标签中配置)
<!-- 一对一查询所有 --> <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>