MyBatis的原理及使用和框架概念的引入
MyBatis的学习
1.什么是框架?
1>什么是框架?
框架(Framework)是整个部分或系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制者的应用骨架。前者是从应用方面而后者是从目的方面给出的定义
简言而之,框架其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统,简单的说就是使用别人搭好的舞台,你来做表演,而且,框架一般是成熟的不断升级的软件
使用框架的好处:框架封装了很多的细节,使开发者可以使用极简的方式实现功能大大提高开发效率
2>三层架构
表现层:用于展示数据的
业务层:是处理业务需求的
持久层:是和数据库交互的
3>持久层技术解决方案
JDBC技术:
Connection,PreparedStatement,ResultSet
Spring的JdbcTemplate:
Spring中对jdbc的简单封装
Apache的DBUtils
它和Spring的JdbcTemplate很像,也是对jdbc的简单封装
以上这些都不是框架JDBC是规范/JdbcTemplate和Apache的DBUtils都只是工具类
JDBC:
public static void main(String[]args){
Connection connection=null;
PreparedStatement ps=null;
ResultSet result=null;
try{
Class.forName("com.mysql.jdbc.Driver");
connection=DriverManger.getCoonection("jdbc;mysql://localhost:3306/Test","root","010313");
}catch(Exception e){
.......
}
}
2.MyBatis框架概述
1>简述
(1).mybatis是一个优秀的基于java持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动,创建连接,创建statement等繁杂的过程
(2).mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中的sql动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql语句最终由mybatis框架执行sql并将结果映射为java对象并返回
(3).采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作
(4).mybatis是一个持久层框架,用java编写的它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身而无需关注注册驱动,创建连接等繁杂过程它使用了ORM思想实现了结果集的封装
ORM(Object Relational Mappging)对象关系映射 简单的说:就是把数据库表和实体类及实体类的属性对应起来让我们操作实体类就实现操作数据库表
[实体类中的属性和数据库表中的字段名保持一致]
2>Mybatis环境搭建和入门案例
Mybatis的环境搭建:
第一步:创建Maven工程并导入坐标
第二步:创建实体类和dao的接口
第三步:创建Mybatis的主配置文件 SqlMapConfig.xml
第四步:创建映射配置文件
环境搭建的主意事项;
1.创建IUserDao.xml和IUserDao.java时名称是为了和我们之前的知识保持一致在MyBatis中它把持久层的操作接口名称和映射文件也叫做Mapper 所以IUserDao和IUserMapper 是一样的
2.在IDEA中创建目录的时候,它和包是不一样的包在创建时:com.itxu.dao它是三层的结构 目录在创建的时候却是一层目录
3.Mybatis的映射配置文件必须和dao接口的包结构相同
4.映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
5.映射配置文件的操作配置,id属性的取值必须是dao接口的方法名
当我们遵从了第三四五点,我们在开发中级不需要写dao的实现类
MyBatis基于代码模式实现Dao的功能:
package com.itxu.test.MybatisTest;
import cn.mybatis.Dao.IUserDao;
import cn.mybatis.domain.User;
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.InputStream;
import java.util.List;
/**
* MyBatis入门案例
*/
public class MyBatisTest {
public static void main(String[] args) throws IOException {
//1.读取配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
/**
* 第一个:使用类加载器,它只能读取类路径的配置文件
* 第二个:使用ServletContext对象的getRealPath();
* */
//2.创建SqlSessionFactory工厂
/**
*
* 创建工厂MyBatis使用了/构建者模式
* 构建者模式:把对象的创建细节隐藏,是使用者直接调用方法即可拿到对象
*
* 生产了SqlSession使用了工厂模式
* 优势:解耦(降低类之间的依赖关系)
* */
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//3.使用工厂生产SqlSession对象 优势:解耦(降低类之间的依赖关系)
SqlSession session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
/**
*
* 创建Dao接口实现模式实现了代理模式
* 优势:不更改源码的基础上对已有方法的加强
* */
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.fingetUser();
for (User user : users)
{
System.out.println(user);
}
//6.释放资源
session.close();
is.close();
}
}
1.读取配置文件
2.创建SqlSessionFactory工厂
3.创建SqlSession
4.创建Dao接口的代理对象
5.执行Dao中的方法
6.释放资源
注意:不要忘记在映射配置文件中告知MyBatis要封装到哪个实体类中
配置的方式:指定实体类的全限定类名
3.使用XML和注解
1>使用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="cn.mybatis.Dao.IUserDao">//指定实体类名的全限定类名
//<!--配置查询所有-->
<select id="fingetUser" resultType="cn.mybatis.domain.User">
select * from user;
</select>
</mapper>
<mappers>
//指定映射配置文件的位置,映射配置文件指的是每个Dao独立的配置文件
<mapper resource="com/itxu/Dao/IUserDao.xml"></mapper>
</mappers>
2>使用注解来配置
mybatis基于注解的入门案例:
把IUserDao.xml移除,在Dao接口的方法上使用@Select,并且指定SQL语句同时需要在SqlMapConfig.xml中的mapper的配置中使用class属性指定Dao接口的全限定类名
我们在实际开发中都是越简便越好都是采用不写Dao实现类的方式不管是用xml还是注解配置 但是mybatis是支持编写实现类的
@Select("select * from user")
<mappers>
//如果是用注解的话,此处应该使用class属性来指定dao的全路径
<mapper class="cn.mybatis.Dao.IUserDao"><mapper>
</mappers>
4.MyBatis回顾
1>第一步:
SqlSessionFactoryBuilder接收SqlMapConfig.xml文件流,构建出SqlSessionFactory对象
2>第二步:
SqlSessionFactory读取SqlMapConfig.xml中连接数据库和mapper映射信息用来生产真正操作数据库的SqlSession对象
3>第三步:
SqlSession对象有两大作用:①生成接口代理对象②定义通用增删改查方法
4>第四步:
作用①:在SqlSessionImpl对象的getMapper方法中分两步来实现。第一:先用SqlSessionFactory读取数据库连接信息创建Connection对象 第二:通过jdk代理模式创建出代理对象作为getMapper方法返回值,这里主要工作是在创建代理对象时第三个参数处理类里面得到sql语句执行对应CURD操作
作用②:在SqlSessionImpl对象中提供selectList()方法[当然实际mybatis框架中海油selectOne,insert等方法]这些方法内也分为两步
第一:用SqlSessionFactory读取数据库连接信息创建出jdbc的Connection对象 第二:直接得到Sql语句,使用jdbc的Connection对象进行对应CURD操作
5>第五步:
封装结果集:无论使用分支一生成代理对象还是直接使用分支二提供的通用CRUD方法我们都要对返回的数据库结果集进行封装编程java对象返回给调用者所以我们还必须要知道调用者所需要的返回类型
总结:通过以上流程不难看出,无论是让mybatis帮我们创建代理对象还是直接使用mybatis提供的CRUD方法,其本质都是得到jdbc的Connection对象,执行对应得Sql语句,最终封装结果集。只是注解和xml配置文件两种开发模式在传递sql语句和返回值类型的方式上都有所差异
注解方式: @Select("select * from user")
public List<User>finall();
xml文件配置的方式:
<mapper namespace="com.itxu.mapper.UserMapper">
<select id="finall" resultType="cn.mybatis.domian.User">
select * from user;
</select>
</mapper>
5.使用MyBatis完成CURD
1>查询所有操作
<!--配置查询所有-->
<select id="fingetUser" resultType="cn.mybatis.domain.User">
select * from user;
</select>
2>添加信息操作
<!--保存用户-->
<insert id="saveUser" parameterType="cn.mybatis.domain.User">
insert into user(username,address,sex,birthday)values (#{username},#{address},#{sex},#{birthday});
</insert>
3>更改信息操作
<!--更新用户-->
<update id="updateUser" parameterType="cn.mybatis.domain.User">
update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday}
where id=#{id};
</update>
4>删除信息操作
<!--删除用户-->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{userid};
</delete>
5>根据单个信息来查询数据
<!--根据id查询用户-->
<!--同时需要返回结果集需要告诉返回值是什么类型-->
<select id="getUserByid" parameterType="java.lang.Integer" resultType="cn.mybatis.domain.User">
select * from user where id=#{userid};
</select>
6>模糊查询的操作
注意:要在调用该方法的时候添加% %
<!--使用模糊查询查询到用户的数据-->
<select id="getUserbyname" parameterType="String" resultType="cn.mybatis.domain.User">
select * from user where username like #{name};
</select>
7>使用聚合函数查询记录的总数
<!--使用聚合函数count查询user表中的用户数据-->
<select id="userCount" resultType="int">
select count(id)from user;
</select>
注意:
select * from user where username like '%${value}%';
执行的Sql语句是 select * from user where username like'%王%'(使用的是Statement的拼接S ql)
select *from user where username like #{name};
执行的Sql语句是 select * from user where username like ?;(使用的是prepateStatement的占位符)
8>在插入操作之前的到添加数据的编号
<!--配置插入操作后获取插入数据的返回值id-->
<!-- keyProperty:实体类名称 order:执行顺序 resultType:返回类型-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id();
</selectKey>
9>#{}和${}的区别
#{}表示一个占位符号
通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转化#{}可以有效的防止Sql注入,#{}可以接收简单类型值或pojo属性值,如果paremeterType传输单个简单类型值,#{}括号中可以是value或是其他值
${}表示拼接字符串
通过${}可以将paramererType传入的内容拼接在Sql中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value
注:源码中指定了读取的key的名字就是value所以我们就只能叫做value
在实体类名和数据名不同的时候怎么操作
1>在配置数据库文件的时候更改Sql语句(执行效率更快)
select * from user where username as userName;
2>在配置数据库文件中添加对应关系(执行顺序相对慢)
<!--配置查询结果的列名和实体列属性的对应关系-->
<resultMap id="userMap" type="cn.mybatis.domain.User">
<!--主键字段的对应-->
<id property="userid" column="id"></id>
<!--非主键字段的对应-->
<result property="userName" column="username"></result>
<result property="userAddress" column="address"></result>
<result property="userSex" column="sex"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
在需要调用的属性添加resultMap="userMap";
6.OGNL表达式
OBject Graphic Navigation Language(对象图导航语言)
通过对象的取值方法来获取数据,在写法上把get省略了
1>获取用户的名称
user.getUsername();
user.username;
mybatis中为什么能直接写username而不是user因为在parameterType中已经提供了属性所属的类,所以此时不需要对象名
//用于执行语句判断、批量操作、映射一对多、多对多关系等等
7.关于配置的加强
1>优化数据库连接信息的操作使用外部文件
<!--配置properties
可以在标签内部配置数据库连接的信息,也可以通过属性引用外部配置文件新
resource:用于指定配置文件的路径按照类路径的写法来写并且必须存在类路径下
url属性:要求按照url的写法来写地址
URL:Unifom Resource Locator:统一资源定位符,它是可以唯一标志一个资源的位置(更精确
http://localhost:8080/mybatis/demo
写法:协议 主机 端口 URI 组成
URI:Unifom Resource Identifier 统一资源标识符 它是在应用中可以唯一定位一个资源
-->
<properties resource="jdbcConfig.properties"></properties>
//改变DateSource的连接信息
<dataSource type="POOLED">
<!--配置连接数据库的基本信息-->
<!--jdbc:mysql://localhost:3306/eesy_mybatis-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
2>typeAliases标签和package标签
<!--使用typeAliases配置别名,它只能配置domian中类的别名-->
<typeAliases>
<!--typeAlias用于配置别名type属性指定的是实体类的全限定类名-->
<!--alias属性指定别名,当指定了别名就不在区分大小写-->
typeAlias type="cn.mybatis.domain.User" alias="user"></typeAlias>
<!--用于指定要配置别名的包当指定之后该包下的实体类都会注册别名,并且类名就是别名不再区分大小写-->
<package name="cn.mybatis.domain"></package>
</typeAliases>
3>关于Mappers标签的优化
<mappers>
<!--<mapper resource="com/itxu/Dao/IUserDao.xml"></mapper>-->
<!--是用于指定Dao接口所在的包当指定完成之后就不需要在写resource,class-->
<package name="cn.mybatis.Dao"></package>
</mappers>
8.连接池
1>关于连接池的简介
连接池:我们在实际开发都会使用连接池,因为他可以减少我们获取连接所消耗的时间,就是用于存储连接的一个容器(容器就是一个集合对象,该集合必须是线程安全的不能是两个线程拿到同一个连接,同时该线程还必须实现队列的特性,先进先出)
2>mybatis中的连接池
连接池提供了三种配置方式:
主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式
type的取值:
POOLED:采用传统javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
UNPOOLED:采用传统的获取连接的方式,虽然也实现了Javax.sql.DataSource接口,但是并没有使用池的思想
JNDI:采用服务器提供的JDNI实现来获取DataSource对象不同的服务器所能拿到的DataSource是不一样的如果不是web或者maven的war工程是不能使用的我们课程中使用的是tomcat服务器 采用的连接池就是dbcp连接池
Mybatis中的事务:
是通过sqlsession对象的commint方法和rollback方法实现事务的提交和回滚
9.动态Sql语句
1>
动态SQLMyBatis最强大的特性之一一直是它的动态SQL功能。如果您有使用JDBC或任何类似框架的经验,就会理解有条件地将SQL字符串连接在一起是多么痛苦,请确保不要忘记空格或忽略列列表末尾的omma。处理动态SQL可能非常困难。虽然使用动态SQL永远不会有什么好处,但是MyBatis使用了一种强大的动态SQL语言,可以2>
2>
在任何映射的SQL语句中使用,这无疑改善了这种情况。
3>
使用过JSTL或任何类似的基于XML的文本处理器的人都应该熟悉动态SQL元素。在MyBatis的早期版本中,有很多需要了解和理解的元素。MyBatis大大改进了这一点,现在只有不到一半的元素。处理。MyBatis使用强大的基于OGNL的表达式来消除大部分其他元素:
if
choose(when,otherwise)
trim(where,set)
foreach
4>动态Sql之<if>标签
<select id="findByUser" resultType="user" parameterType="user">
select * from user where1=1
<if test="username!=null and username!=''">
and username like #{username}
<if test="address!=null">
and address like #{username}
</select>
注意:<if>标签的test属性中写的是对象的属性名,如果包装类的对象要使用OGNL表达式的写法另外要注意where 1=1的作用(使条件为真)
5>动态标签之<where>标签
为了简便上面 where 1=1的操作我们可以使用where来简便
扩展:抽取查询语句中的重复语句:最终达到Sql可以重用的作用
<!--抽取重复的Sql语句-->
<sql id="defaultUser">
select * from user
</sql>
<select id="findByUser" resultType="user" parameterType="user">
<include refid="defaultUser"></include>
<where>
<if test="username!=null and username!=''">
and username like #{username}
<if test="address!=null">
and address like #{username}
<where>
</select>
注意:在编写Sql的时候尽量不要去加分号
/*The error may exist in com/itxu/Dao/IUserDao.xml
### The error may involve cn.mybatis.Dao.IUserDao.findUserInIds-Inline
### The error occurred while setting parameters
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ';*/
6>动态标签之<foreach>标签
当需求发生改变:
传入多个 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)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。 这样我们将如何进行参数的传递?
持久层Dao映射配置的编写:
<!--查询所在用户的id集合-->
<select id="findInids" resultType="user" parametrType="cn.mybatis.domian.QueryVo">
<!--select * from user where id in(1,2,3,4)-->
<include refid="defaultUser"></include>
<where>
<if text="ids!=null and ids.size()>0"></if>
<foreach collection="ids" open="id in(" close=")" item="uid" separator=",">
#{uid}
</foreach>
</where>
</select>
Sql语句:select * from user where id in(?);
<foreach>标签用于遍历集合他们的属性分别是:
collection:代表要遍历的集合元素,注意编写的时候不要写${}
open:代表语句的开始部分
close:代表语句的结束部分
item:代表遍历集合的每个元素生成的变量名
separator:代表分隔符
9.Mybatis中的多表查询
1>表之间的关系有几种
一对多
多对一
一对一
多对多
举例:
用户和订单就是(一对多)
一个用户可以下多个订单/多个订单属于同一个用户
人和身份证就是(一对一)
一个人只能有一个身份证号/一个身份证号只能有一个人
学生和老师就是(多对多)
一个学生可以被多个老师教过/一个老师可以教多个学生
特例:
如果拿出每一个订单/他都只能属于一个用户所以Mybatis中就把多对一看成了一对一
mybatis中的多表查询:
一个用户可以有多个账户/一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
1.建立两张表:用户表和账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
2.建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出一对多的关系
3.建立两个配置文件
4.实现配置:
当我们查询用户时可以同时得到用户下所包含的账户信息
当我们查询账户时,可以同时得到账户的所属用户信息
实现多对多关系的案例:
1.建立两张表:用户表,角色表
让用户和角色表具有多对多关系,需要使用中间表,中间表中包含各自的主键,在中间表是外键
2.建立两个实体类:用户实体类和角色实体类
让用户和角色的实体能体现出来多对多的关系
各自包含对方一个集合引用
3.建立两个配置文件
用户的配置文件
角色的配置文件
4.实现配置
当我们查询用户的时候,可以同时得到用户所包含的角色信息
当我们查询角色的时候,可以同时得到角色的所赋予的用户信息
2>.一对一关系
//从表实体应该包含主表实体的对象引用
private User user;
并且需要编写配置文件
<resultMap id="accountUserMap" type="cn.mybatis.domain.Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--一对一的关系映射-->
<association property="user" column="uid" javaType="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</association>
</resultMap>
SQL: select a.*,u.username,u.address from account a,user u where u.id=a.uid;
3>.一对多关系
//主体表中应该包含从表的集合
private List<Account> accounts;
并且需要编写配置文件
<!--定义User的ResultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!--配置User对象中account集合的映射-->
<collection property="accounts" ofType="Account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
Sql: SELECT * from user u LEFT OUTER JOIN account a on u.id=a.uid;
4>多对多关系
//通过中间表建立关系分别在主表和从表中添加相应的集合
private List<User>users;
private List<Role>roles;
<!--在双方的配置文件配置对应得ResultMap和collection-->
IUserDao.xml
<resultMap id="UserRoleMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<collection property="roles" ofType="role"> //定义集合
<id property="roleid" column="id"></id>
<result column="role_name" property="rolename"></result>
<result column="role_desc" property="roledesc"></result>
</collection>
</resultMap>
IRoleDao.xml<和mapper同>
<resultMap id="RoleMap" type="role">
<id property="roleid" column="id"></id>
<result property="rolename" column="role_name"></result>
<result property="roledesc" column="role_desc"></result>
<collection property="users" ofType="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</collection>
</resultMap>
Sql: select u.*,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;
双左联双查询条件
10.JNDI的知识扩展
JNDI(Java Naming and Directory Interface),java命名和目录接口和目录接口是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互,目录服务是命名服务的一种自然扩展两者之间的关键差别是目录服务中对象不但可以有名称还可以有属性(例如,用户有email地址)而命名服务对象却没有
作用:模仿Windows系统的注册表
<!--
<Resource
name="jdbc/eesy_mybatis" 数据源的名称
type="javax.sql.DataSource" 数据源类型
auth="Container" 数据源提供者
maxActive="20" 最大活动数
maxWait="10000" 最大等待时间
maxIdle="5" 最大空闲数
username="root" 用户名
password="1234" 密码
driverClassName="com.mysql.jdbc.Driver" 驱动类
url="jdbc:mysql://localhost:3306/eesy_mybatis" 连接url字符串
/>
1.在META-INF目录中建立一个名为context.xml的配置文件
2.修改SqlMapConfig.xml
<dataSource type="JNDI">
<property name="data_source" value="java:comp/env/jdbc/eesy_mybatis"/>
</dataSource>
11.Mybatis中的延迟加载和立即加载/缓存
1>Mybatis中的延迟加载
问题:在一对多种,当我们有一个用户,它有100个账户在查询用户的时候我们要不要把关联的账户查出来?当查询账户的时候要不要把关联的用户查出来
在查询用户时,用户下的账户信息应该是什么,什么时候使用,什么时候查询的在查询账户时,账户的所属信息应该是随着账户查询时一起查询出来
延迟加载
在真正使用数据时才发起查询不用的时候不查询按需查询(懒加载)
立即加载
不管用户用不用,只要一调用方法马上发起查询
在对应得四种表关系中:一对多,多对一,一对一,多对多
关联的数据是一通常情况下我们都是采用立即加载
关联的数据是多通常情况下我们都是采用缓存加载
2>在一对一情况下执行延迟加载
同样我们也可以在一对多关系配置的<collection>结点中配置延迟加载策略。 <collection>结点中也有 select 属性,column 属性
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
//更改Mappeer中的映射配置
<!--配置User对象中account集合的映射-->
IAccountMapper.xml
<association property="user" column="uid" javaType="user" select="cn.mybatis.Dao.IUserDao.getUserByid"></association>
3>在一对多的情况下执行延迟加载
IUserMapper.xml (一)
<collection property="accounts" ofType="account" select="cn.mybatis.Dao.IAccountDao." column="id"></collection>
4>缓存
1.缓存:存在于内存中的临时数据
2.为什么使用缓存:减少和数据库的交互次数,提高执行效率
3.适用于缓存:经常查询并且不经常改变的数据的正确与否对最终的结果影响不大的
4.不适用于缓存的:经常改变的数据数据的正确与否对最终结果影响很大的如:商品的库存和银行的汇率
1).mybatis中的一级缓存
它指的是Mybatis中SqlSession对象的缓存当我们执行查询之后查询的结果会同时存入到SqlSession为我们提供的一块区域中该区域的结构是Map集合当我们再次查询同样的数据mybatis会先去SqlSession中查询是否有有的话直接拿出来当SqlSession对象消失时mybatis中的一级缓存也就消失了
session.clearCache(); 用来清除缓存
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等
5>二级缓存
指的是Mybatis中的SqlSessionFactory对象的缓存.由同一个SqlSessionFactory对象创建的SqlSession共享其缓存
二级缓存的使用使用步骤
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml配置)
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
第三步:让当前的操作支持二级缓存(在select标签中配置)
二级缓存:存放的内容是数据,而不是对象
12.Java序列化接口的作用
1>Java序列化接口Serializable的作用
一个对象有对应得一些属性,把这个对象保存在硬盘上的过程叫做持久化 对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值(因为静态static的东西在方法区)序列化能把堆内存中的对象的生命周期延长,做持久化操作当下次再需要这个对象的时候我们就不用new 了直接从硬盘中读取就可以了(存储到硬盘是一个文件,不需要我们去解析如果用记事本打开解析会出现乱码,解析要用特定的方式不用我们管我们只需要读取)把对象存储到硬盘上的一个文件中这个文件的标准扩展名是(object)
2>什么样的数据会进行序列化到硬盘进行持久化
1)在很多框架中就会有这种object结尾的文件因为很多对象都不创建,创建起来太麻烦而且对象的值你不知道,框架封存在.object文件中,直接读取这个文件中的这个值就行了不需要传这个值
在搞web开发的时候一些类就需要实现序列化接口因为服务器就会对你的对象进行临时的本地存储它怕服务器崩溃了以后你的会话就会消失所以存储在了硬盘上你重新启动服务器恢复之前的会话,恢复对象,你之前运行的东西都在
2).对某些特定的对象,比如:数据库连接对象,存储特定数据的对象,这样对象你不想创建他们,想存储起来让他们的生命周期延长可以把他们放在硬盘当中每次系统启动的时候都到.object读取对象里面的数据,这个时候就可以把他们序列化来完成
/*Serializable:用于给被序列化的类加入ID号。
用于判断类和对象是否是同一个版本。 */
transient:非静态数据不想被序列化可以使用这个关键字修饰。
3>可能会产生的异常
可能抛出的错误 @throws ClassNotFoundException
如果只有obj.object 这个文件能不能把其中的对象Person取出来,因为任何对象在堆内存中创建都必须依赖于该对象所属的类文件(class文件),如果仅仅给了obj.object,这个里面有Person对象的字节码,可是取出的时候你内存中并没有Person.class文件,没有,所以取不出来,所以必须要有obj.object文件和Person.class文件.(所以有一个ClassNotFound异常)
关于程序中的类 ObjectInputStream和ObjectOutputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化(意思就是ObjectInputStream只能读取ObjectOutputStream的)
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象的持久存储。
关于SerializableID
SerializableID号是根据类的特征和类的签名算出来的.为什么ID号那么长,是因为为了避免重复.所以Serializable是给类加上id用的. 用于判断类和对象是否是同一个版本。
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值. 原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException
13.Mybatis基于注解开发的深入解析
>>M共有四种注解方式
@SELECT @UPDATE @INSERT @DELETE
1>查询所有
@Select("select * from user")
2>添加数据
@INSERT("INSERT INTO USER(username,address,sex,birthday) VALUES(#{username},#{address},#{sex},#{birthday})")
3>修改数据
@UPDATE("update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}")
4>删除数据
@DELETE("delete from user where id=#{id}")
5>查询一个用户
@Select("select * from user where id=#{id}")
6>模糊查询
@Select("select * from user where username like #{username}")
@Select("select * from user where username like '%${value}%'")
7>实体类名与数据库名不相同的解决方案
@Results(id = "userMap",value = {
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
})
@ResultMap(value={"userMap"})//引用上边的注解
8>Mybatis基于注解开发的一对多或者是多对一的注解配置
一: @Result(property = "user",column = "uid",one=@One(select="cn.mybatis.Dao.UserDao.findUserByid",fetchType= FetchType.EAGER))
多: @Result(property = "accounts",column = "id",
many = @Many(select = "cn.mybatis.Dao.AccountDao.findUserByuid",
fetchType = FetchType.LAZY))
9>Mybatis基于注解开发配置二级缓存
本文作者:张三Blog
本文链接:https://www.cnblogs.com/zhangsan-plus/p/16503316.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步