day03-mybatis随堂笔记
一、mybatis的延迟加载
1.概念:
延迟加载也叫懒加载 一开始的时候不会进行加载,当真正需要的时候才开始加载执行
立即加载,不管什么情况都会一次性的全部加载出来
2.使用延迟加载或者立即加载的时机?
按需加载:
1.当查询账户的时候一定要关联查询用户,这个时候建议使用立即加载
2.当查询用户的时候不需要立即关联账户,这个时候不需要立即加载,可以使用懒加载
3.在实际开发中级联查询的时候使用加载方式的时机?
一对一,多对一 一般使用立即加载
一对多,多对多 一般使用懒加载(延迟加载)
4.延迟加载的好处:
节省内存资源,效率比较快
5.使用懒加载和立即加载:
5.1立即加载:
mybatis的默认加载方式就是立即加载
级联的另外一种方式配置,根据账户信息关联用户信息,一对一操作
第一步,编写IAccountDao
List<Account> findAll();
第二步,编写IAccountDao.xml
<resultMap id="accountUserMap" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的关系映射:配置封装user的内容
select属性指定的内容:查询用户的唯一标识:
column属性指定的内容:用户根据id查询时,所需要的参数的值
-->
<association property="user" column="uid" javaType="user"
select="com.itheima.dao.IUserDao.findById">
</association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
select * from account
</select>
第三步,编写IUserDao
User findById(Integer userId);
第四步,编写IUserDao.xml
<!-- 根据id查询用户 -->
<select id="findById" parameterType="INT" resultType="user">
select * from user where id = #{uid}
</select>
第五步,编写AccountTest测试类
/**
* 测试查询所有
*/
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for(Account account : accounts){
System.out.println("--------每个account的信息------------");
System.out.println(account);
System.out.println(account.getUser());
}
}
5.2懒加载:
要想是使用懒加载,必须不能使用多表联合查询的sql语句,必须使用单表查询语句
案例1:
根据账户信息关联用户信息,一对一操作(基于上面的代码基础之上)
第一步,在sqlMapConfig.xml中添加settings配置
<!--配置参数-->
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
<setting name="lazyLoadTriggerMethods" value=""></setting>
</settings>
第二步,测试
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
}
第三步,测试结果
延迟加载
[外链图片转存失败(img-q6emX1iW-1565187729641)(assets\1558753027820.png)]
立即加载
[外链图片转存失败(img-MbOLwhsh-1565187729645)(assets\1558753057125.png)]
案例2:
根据用户信息关联账户信息,一对多操作(基于上面的代码基础之上)
第一步,开启延迟加载在sqlMapConfig.xml
<!--配置参数-->
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
<setting name="lazyLoadTriggerMethods" value=""></setting>
</settings>
第二步,编写IUserDao
List<User> findAll();
第三步,编写IUserDao.xml
<!-- 定义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对象中accounts集合的映射 -->
<collection property="accounts" ofType="account"
select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"></collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user
</select>
第四步,编写IAccountDao
/**
* 根据用户id查询账户信息
* @param uid
* @return
*/
List<Account> findAccountByUid(Integer uid);
第五步,编写IAccountDao.xml
<!-- 根据用户id查询账户列表 -->
<select id="findAccountByUid" resultType="account">
select * from account where uid = #{uid}
</select>
第六步,测试类UserTest
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
}
延迟加载结果
[外链图片转存失败(img-Ts2j2VFo-1565187729647)(assets\1558754523139.png)]
立即加载结果
[外链图片转存失败(img-Ek0qJdWU-1565187729650)(assets\1558754589322.png)]
二、mybatis的缓存
缓存是运行在内存中的临时数据的一种统称。
缓存的意义是为了减少访问数据库的压力而存在的
mybatis的缓存分为一级缓存和二级缓存
一级缓存是SqlSession级别的缓存,缓存的数据只在SqlSession内有效
二级缓存是mapper级别的缓存,同一个namespace共用这一个缓存,所以对SqlSession是共享的
一级缓存:
如果从同一个sqlSession中生成实体类则是同一个内存中加载的,第一次的时候由于缓存中没有临时数据,那么就会从数据库中查询,第二次的时候就不在从数据库中查询了,从sqlSession缓存中查询。
可以使用sqlSession.close()关闭缓存,或者sqlSession.clearCache();清空缓存
当mybatis执行完修改,删除,和新增之后,那么当前sqlSession一级缓存就已经自动清空,这个时候再使用sqlSession一级缓存去查询,此时没有数据,mybatis就会自动去查询数据库。
问题:
在一个sqlSessionFactory中可以创建多个sqlSession(一级缓存),一般情况下在一个项目中只允许有一个sqlSessionFactory
二级缓存:
二级缓存是mapper级别的缓存,同一个namespace共用这一个缓存,所以对SqlSession是共享的
其实的真正执行者CachingExecutor是Executor**的装饰者
使用步骤:
第一步,在sqlMapConfig.xml中设置全局开启二级缓存的设置,默认就是开启
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
第二步,在mapper标签中开启局部二级缓存
[外链图片转存失败(img-WQi2DRml-1565187729651)(assets\1558765694518.png)]
第三步,在调用的sql语句所在的select标签中使用缓存
[外链图片转存失败(img-PKL7qzIh-1565187729654)(assets\1558765743472.png)]
第四步,测试
[外链图片转存失败(img-Ntq14ZdV-1565187729656)(assets\1558765782821.png)]
[外链图片转存失败(img-GkqSeBd8-1565187729658)(assets\1558765981357.png)]
三、mybatis的注解开发(掌握)
xml版和注解版区别:
xml版:必须要有mybatis的核心配置文件sqlMapConfig.xml和sql映射文件xxMapper.xml(xxDao.xml)
注意:dao接口名称建议和实体类映射文件xxDao.xml文件名称一致
注解版:必须要有mybatis的核心配置文件sqlMapConfig.xml。
没有了sql映射文件xxMapper.xml(xxDao.xml)。
问题:
使用注解版开发,只需要编写dao接口即可,至于实现的话,我们会采用注解形式在dao接口的方法之上实现。
注解版开发一般在企业中为了适应springboot(微服务架构),因为微服务架构(写的少做的多)没有xml文件,在微服务架构中项目中只有一个配置文件.perperties
环境搭建:
核心配置文件sqlMapConfig.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">
<configuration>
<!-- 引入外部配置文件-->
<properties resource="jdbcConfig.properties"></properties>
<!--配置别名-->
<typeAliases>
<package name="com.itheima.domain"></package>
</typeAliases>
<!-- 配置环境-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 指定带有注解的dao接口所在位置 -->
<mappers>
<!-- <mapper class="com.itheima.dao.IUserDao"></mapper>-->
<package name="com.itheima.dao"></package>
</mappers>
</configuration>
[外链图片转存失败(img-vdBMm7ln-1565187729661)(assets\1558767901669.png)]
注解版单表CRUD操作
查询操作:
/**
* 查询所有用户
* @Select注解表示查询注解
* @Select()括号中默认是value属性值,类型是String[]
* 如果说value属性值只有一个,那么value可以省略不写,@Select("select * from user")
* 但是如果value属性值是多个那么value不可以省略@Select(value={"select * from user","select * from user"})
*/
@Select("select * from user")
List<User> findAll();
新增操作:
/**
* 保存用户
* @param user
* @Insert表示新增的注解
* #{参数}必须要和当前接口方法中参数实体类中的相对应的属性名称一致
*/
@Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);
修改操作:
/**
* 更新用户
* @param user
*/
@Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")
void updateUser(User user);
删除操作:
/**
* 删除用户
* @param userId
*/
@Delete("delete from user where id=#{id} ")
void deleteUser(Integer userId);
单一查询操作:
/**
* 根据id查询用户
* @param userId
* @return
*/
@Select("select * from user where id=#{id} ")
User findById(Integer userId);
模糊查询操作:
/**
* 根据用户名称模糊查询
* @param username
* @return
*/
@Select("select * from user where username like #{username} ")
/*@Select("select * from user where username like '%${value}%' ")*/
List<User> findUserByName(String username);
查询总数操作:
/**
* 查询总用户数量
* @return
*/
@Select("select count(*) from user ")
int findTotalUser();
注解版开发流程
注解版多表级联操作
分析:
用户和账户关系:
用户和账户可以作为一对多关系
账户和用户可以作为多对一和一对一关系
演示一对一关系级联:
查询账户,包含用户信息
第一步,在账户实体类中加入用户实体类作为属性存在
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//多对一(mybatis中称之为一对一)的映射:一个账户只能属于一个用户
private User user;
第二步,编写IAccountDao接口
/**
* 查询所有账户,并且获取每个账户所属的用户信息
* @return
* property表示实体类中的属性名称
* column表示实体类属性相对应的数据库表字段名称
* one表示多对一(一对一)的级联关系配置
* one=@One(select="com.itheima.dao.IUserDao.findById",关联查询IUserDao接口中的findById得方法
fetchType= FetchType.EAGER)表示立即加载
*/
@Select("select * from account")
@Results(id="accountMap",value = {
@Result(id=true,column = "id",property = "id"),
@Result(column = "uid",property = "uid"),
@Result(column = "money",property = "money"),
@Result(property = "user",column = "uid",
one=@One(select="com.itheima.dao.IUserDao.findById",
fetchType= FetchType.EAGER))
})
List<Account> findAll();
第三步,编写IUserDao接口中的findById方法
/**
* 根据id查询用户
* @param userId
* @return
*/
@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
第四步,编写测试类
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for(Account account : accounts){
System.out.println("----每个账户的信息-----");
System.out.println(account);
System.out.println(account.getUser());
}
}
演示一对多关系级联:
查询用户,包含账户信息
第一步,编写用户实体类信息
public class User implements Serializable{
private Integer userId;
private String userName;
private String userAddress;
private String userSex;
private Date userBirthday;
//一对多关系映射:一个用户对应多个账户
private List<Account> accounts;
第二步,编写IUserDao接口
/**
* 查询所有用户
* @return
* 如果实体类中的属性名称和数据库表字段如果一致的话,那么 @Result可以省略
* many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
* 表示一对多级联查询,
* fetchType = FetchType.LAZY加载方式为懒加载
*/
@Select("select * from user")
@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"),//除主键之外的其他字段的匹配
//级联
@Result(property = "accounts",column = "id",
many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();
第三步,编写IAccountDao接口中的findAccountByUid方法
/**
* 根据用户id查询账户信息
* @param userId
* @return
*/
@Select("select * from account where uid = #{userId}")
List<Account> findAccountByUid(Integer userId);
第四步,测试
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
/* for(User user : users){
System.out.println("----每个用户的信息-----");
System.out.println(user);
System.out.println(user.getAccounts());
}*/
}
总结:
分析表与表之间的关联关系?
用户表和账户表
[外链图片转存失败(img-PZNKiAa8-1565187729663)(assets/1559383613320.png)]
表关系分析:
如果说从用户表去查询账户表,在mybatis中称之为一对多(一个用户拥有多个账户)
如果说从账户表去查询用户表,在mybatis中称之为多对一(多个账户在同一个用户名下)或者一对一(一个账户在同一个用户下)操作
sql语句分析:
查询账户,包含用户
1.查询账户,select * from account(包含id,uid,money)
2.包含用户,select * from user where id=uid (这个uid是account表中的外键)
查询用户,包含账户
1.查询用户,select * from user(包含id,username,birthday,sex,address)
2.包含账户,select * from account where uid=id(这个id是user表中的主键)
mybatis的一级缓存?
sqlSession,代理对象由一级缓存产生,
创建:加载核心配置文件的时候,打开opensession的时候,创建
失效:close(),clearCache(),执行新增,修改,删除之后,一级缓存失效
mybatis注解一对一和一对多开发?
1.一对一:查询账户,包含用户
[外链图片转存失败(img-wfnSdWPd-1565187729666)(assets/1559384634141.png)]
2.一对多:查询用户,包含账户
[外链图片转存失败(img-CD93GO82-1565187729667)(assets/1559384998061.png)]
s中称之为多对一(多个账户在同一个用户名下)或者一对一(一个账户在同一个用户下)操作
sql语句分析:
查询账户,包含用户
1.查询账户,select * from account(包含id,uid,money)
2.包含用户,select * from user where id=uid (这个uid是account表中的外键)
查询用户,包含账户
1.查询用户,select * from user(包含id,username,birthday,sex,address)
2.包含账户,select * from account where uid=id(这个id是user表中的主键)
mybatis的一级缓存?
sqlSession,代理对象由一级缓存产生,
创建:加载核心配置文件的时候,打开opensession的时候,创建
失效:close(),clearCache(),执行新增,修改,删除之后,一级缓存失效
mybatis注解一对一和一对多开发?
1.一对一:查询账户,包含用户
[外链图片转存中…(img-wfnSdWPd-1565187729666)]
2.一对多:查询用户,包含账户
[外链图片转存中…(img-CD93GO82-1565187729667)]