第二次总结
所学内容:
## 1.CRUD1.1.C
<!-- 保存用户-->
<insert id="saveUser" parameterType="com.itcast.domain.User">
insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})
</insert>
<!-- 保存用户-->
<insert id="saveUser" parameterType="com.itcast.domain.User">
<!-- 配置插入操作后,获取插入数据的id-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})
</insert>
1.2.R
<!-- 配置查询所有,id是映射的方法名,最后的封号可写-->
<select id="findAll" resultType="com.itcast.domain.User">
select * from user ;
</select>
<!-- 根据id查询用户-->
<select id="findById" parameterType="INT" resultType="com.itcast.domain.User">
select * from user where id = #{userid};
</select>
<!-- 根据名称模糊查询-->
<select id="findByName" parameterType="String" resultType="com.itcast.domain.User">
select * from user where username like #{name}; <!-- 使用的是PrepareStatement的占位符,更好一些-->
<!--select * from user where username like '%${value}%';该参数必须要写成value,使用的是Statement的SQL字符串拼接 -->
</select>
<!-- 查询总用户条数-->
<select id="findTotal" resultType="int">
select count(id) from user;
</select>
1.3.U
<!-- 更新用户-->
<update id="updateUser" parameterType="com.itcast.domain.User">
update user set username = #{username},address = #{address} where id = #{id};
</update>
1.4.D
<!-- 删除用户,当只有一个参数,且是包装类时,这时参数可以随便写,代表占位符-->
<delete id="deleteUser" parameterType="Integer">
delete from user where id = #{uid}
</delete>
2.OGNL表达式
Object Graphic Navigation Language
对象 图 导航 语言
它是通过对象的取值方法来获取数据,在写法上把get给省略了。
比如:我们获取用户的名称
类中的写法:user.getUsername();
OGNL表达式写法:user.username
mybatis中为什么能直接写username而不用user.呢?
因为在parameterType中已经提供了属性所属的类,所以不需要写对象名
3.resultType和resultMap的区别
resultType:实体类属性和数据库列名必须对应,执行效率快
resutMap:根据配置的结果的列名和属性名的对应关系,开发效率快,方便
4.SqlMapConfig配置文件
<?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>
<!-- 配置properties
可以在标签内部配置连接数据库的信息,也可以通过属性引用外部配置文件信息
resource属性:常用的
用于指定配置文件的位置,是按照文件路径的写法来写,并且必须存在于类路径下
url属性:
是要来按照url的写法来写地址
URL:Uniform Resource Locator 统一资源定位符,可以唯一标识一个资源的位置
它的写法:
http://localhost:8080/mybatisserver/demo1Servlet
协议 主机 端口 URI
URI:Uniform Resource Identifier 统一资源标识符,它是在应用中可以唯一定位一个资源的
例如:file:///D:/idea/BackEnd/SSM/Mybatis/day02_01/src/main/resources/jdbcConfig.properties
-->
<properties resource="jdbcConfig.properties">
<!--<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="0103"/>-->
</properties>
<!-- 使用typeAliases配置别名,它只能配置domain中类的别名-->
<typeAliases>
<!-- typeAlias用于配置别名,type属性指定的是实体类全限定类名,alias属性指定别名
当指定了别名,就不再区分大小写-->
<!-- <typeAlias type="com.itcast.domain.User" alias="user"></typeAlias>-->
<!-- 用于指定要配置别名的包,当指定之后,该包下大的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
<package name="com.itcast.domain"/>
</typeAliases>
<!-- 配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池)-->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息-->
<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>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
<mappers>
<!-- <mapper resource="com/itcast/dao/IUserDao.xml"></mapper>-->
<!-- package标签是用于指定dao接口所在的包,当指定了之后,就不需要再写mapper以及resource或class -->
<package name="com.itcast.dao"/>
</mappers>
</configuration>
5.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="com.itcast.dao.IUserDao">
<!-- 配置查询结果的列名和实体类的属性名的对应关系-->
<resultMap id="userMap" type="USER">
<!-- 主键字段的对应,property对应的是java中的属性,严格区分大小写,column是数据库中的列名,windows中不区分大小写,Linux中严格区分大小写-->
<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>
<!-- 配置查询所有,id是映射的方法名,最后的封号可写-->
<!-- <select id="findAll" resultType="com.itcast.domain.User" > -->
<select id="findAll" resultMap="userMap">
<!-- select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user ;-->
select * from user;
</select>
<!-- 保存用户-->
<insert id="saveUser" parameterType="com.itcast.domain.User">
<!-- 配置插入操作后,获取插入数据的id-->
<selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,address,sex,birthday) values(#{userName},#{userAddress},#{userSex},#{userBirthday})
</insert>
<!-- 更新用户-->
<update id="updateUser" parameterType="com.itcast.domain.User">
update user set username = #{userName},address = #{userAddress} where id = #{userId};
</update>
<!-- 删除用户,当只有一个参数,且是包装类时,这时参数可以随便写,代表占位符-->
<delete id="deleteUser" parameterType="Integer">
delete from user where id = #{uid}
</delete>
<!-- 根据id查询用户-->
<select id="findById" parameterType="INT" resultType="user">
select * from user where id = #{userid};
</select>
<!-- 根据名称模糊查询-->
<select id="findByName" parameterType="String" resultType="com.itcast.domain.User">
select * from user where username like #{name}; <!-- 使用的是PrepareStatement的占位符,更好一些-->
<!--select * from user where username like '%${value}%';该参数必须要写成value,使用的是Statement的SQL字符串拼接 -->
</select>
<!-- 查询总用户条数-->
<select id="findTotal" resultType="int">
select count(id) from user;
</select>
<!-- 根据QueryVo的2条件查询用户-->
<select id="findUserByVo" parameterType="com.itcast.domain.QueryVo" resultType="com.itcast.domain.User">
select * from user where username like #{user.userName}
</select>
</mapper>
1.Mybatis连接池与事务
1.1.连接池:
我们在实际开发中都会使用连接池。
因为它可以减少我们获取连接的次数,减少所消耗的时间
连接池就是用于存储连接的一个容器,容器就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到同一连接。
该集合还必须实现队列的特性:先进先出
1.2.mybatis中的连接池:
mybatis连接池提供了3种方式的配置
配置的位置:主配值文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接方式。
type属性的取值:
POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针 对规范的实现。
UNPOOLED 采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接 口,但是并没有使用池的思想。
JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同 的服务器所能拿到的DataSource是不一样的
注意:如果不是web或者maven的war工程,是不能使用的。
黑马课程中使用的tomcat服务器,采用连接池就是dbcp连接池。
1.3.mybatis中的事务
什么是事务
事务的四大特性ACID
不考虑隔离性会产生的3个问题
解决办法:四种隔离级别
mybatis是通过SqlSession中的commit方法和rollback方法实现事务的提交和回滚
2.Mybatis映射文件的SQL深入
2.1.动态SQL < if >标签
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user where 1=1
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
</select>
2.2.where标签
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user
<where>
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
</where>
</select>
2.3.foreach标签
<!-- 根据QueryVo中的Id集合实现查询用户列表-->
<select id="findUserInIds" resultMap="userMap" parameterType="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>
4.sql标签 抽取重复语句,include时,会将sql中的内容替换进去
<sql id="defaultUser">
select * from user<!--这里加;可能会影响到后面的语句-->
</sql>
<!-- 根据QueryVo中的Id集合实现查询用户列表-->
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
<!-- select * from user -->
<include refid="defaultUser"></include>
<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>
3.mybatis中的多表查询
表之间的关系有几种:
一对多
多对一
一对一
多对多
举例:
一个用户可以下多个订单 用户和订单就是一对多
多个订单属于同一个用户 订单和用户就是多对一
一个人只能有一个身份证号 人和身份证号就是一对一
一个身份证号只能属于一个人
一个学生可以被多个老师教 老师和学生之间就是多对多
一个老师可以教多个学生
特例:
如果拿出每一个订单,他都只能属于一个用户。
所以Mybatis就把多对一看成了一对一。
mybatis中的多表查询:
1.示例:用户和账户
一个用户可以有多个账户
一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
1、建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
2、建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出一对多的关系
3、建立两个配置文件
用户的配置文件
账户的配置文件
4、实现配置
当我们查询用户时,可以同时得到用户下所包含的账户信息
当我们查询账户时,可以同时得到账户的所属用户信息
2.示例:用户和角色
一个用户可以有多个角色
一个角色可以赋予多个用户
步骤:
1、建立两张表:用户表,角色表
让用户表和角色表之间具有多对多的关系:需要使用中间表,中间表中包含 各自的主键,在中间表中是外键
2、建立两个实体类:用户实体类和账户实体类
让用户和角色的实体类能体现出来多对多的关系
各自包含对方一个集合引用
3、建立两个配置文件
用户的配置文件
角色的配置文件
4、实现配置
当我们查询用户时,可以同时得到用户下所包含的角色信息
当我们查询角色时,可以同时得到角色的所属用户信息
1.mybatis中的延迟加载
问题:在一对多中,当我们有一个用户,它有100个账户。
在查询用户的时候,要不要把关联的账户查出来
在查询账户的时候,要不要把关联的用户查出来
在查询用户时,用户下的账户信息应该是什么时候使用,什么时候查询的。
在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来。
1.1.什么是延迟加载
在真正使用数据时才发起查询,不用的时候不查询,按需加载(懒加载)
1.2.什么是立即加载
不管用不用,只要一调用方法,马上发起查询。
1.3.对应的四种关系中:一对多,多对一,一对一,多对多
一对多,多对多:通常采用延迟加载。
多对一,一对一:通常情况下我们都是采用立即加载。
2.Mybatis中的缓存
什么时缓存
存在于内存中的临时数据
为什么使用缓存
减少和数据库的交互次数,提高执行效率。
什么样的数据能使用缓存,什么样的数据不能使用
适用于缓存:
经常查询并且不经常改变的。
数据的正确与否对最终结果影响不大的。
不适用于缓存:
经常改变的数据
数据的正确与否对最终结果影响很大的。
例如:商品的库存,银行的汇率,股市的牌价
Mybatis中的一级缓存和二级缓存:
一级缓存:
它指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSesion为我们提供一块区域中
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去 sqlsession中查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
当调用SqlSession的修改,添加,删除,commit(),close()等方法时,就会 清空一级缓存
二级缓存:
它指的是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory 对象创建的SqlSession共享其缓存。
二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
第三步:让当前的操作支持二级缓存(在select标签中配置)
二级缓存存的是数据而不是对象,当从二级缓存中取数据时会创建一个新的对 象,并把数据填充进去。
注意:当我们使用二级缓存时,所缓存的类一定要实现Serializable接口,这种就可以使用序列化方式来保存对象
3.Mybatis的注解开发
细节,当有注解时,并且存在对应的mapper映射文件,不论配不配置mapper,都会报错