配置文件:
全局配置文件(配置数据源、事务运行时信息)
映射文件(执行statement的相关信息,包括sql语句、输入参数、输出结果)
SqlSession(会话)
作用:它是一个面向程序员的接口,程序员通过该接口可以对数据库进行增删改查方法,该接口有一个默认实现:DefaultSqlSession。
executor(执行器)
作用:SqlSession本身不能直接操作数据库,需要通过executor接口来真正的操作数据库。该接口有两个实现:基本执行器、缓存执行器(默认)。
MappedStatement
作用:它封装了执行statement时的信息。包括sql语句、输入参数、输出结果。
谨慎使用${}
${value} 有sql注入风险,会直接拼上从java代码里传来的参数。
<select id="findUsersByName" parameterType="java.lang.String"
resultType="com.itcast.model.User">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>
执行结果:
2017-03-23 22:26:04,087 [main] DEBUG [test.findUsersByName] - ==> Preparing: SELECT * FROM USER WHERE username LIKE '%小%'
2017-03-23 22:26:04,130 [main] DEBUG [test.findUsersByName] - ==> Parameters:
2017-03-23 22:26:04,156 [main] DEBUG [test.findUsersByName] - <== Total: 3
主键返回之自增主键
<!-- 添加用户 -->
<!-- selectKey:查询主键,在标签内需要输入查询主键的sql -->
<!-- order:指定查询主键的sql和insert语句的执行顺序,相当于insert语句来说 -->
<!-- LAST_INSERT_ID:该函数是mysql的函数,获取自增主键的ID,它必须配合insert语句一起使用 -->
<insert id="insertUser" parameterType="com.itcast.model.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO USER (username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address})
</insert>
主键返回之UUID
UUID()函数是mysql的函数。
<insert id="insertUser2" parameterType="com.itcast.model.User">
<selectKey keyProperty="id" resultType="string" order="BEFORE">
SELECT UUID()
</selectKey>
INSERT INTO USER (id,username,birthday,sex,address)
VALUES(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
主键返回之序列
序列也就是sequence,它是Oracle的主键生成策略。
<!-- 自增主键之UUID -->
<insert id="insertUser3" parameterType="com.itcast.model.User">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
SELECT seq.nextval FROM dual
</selectKey>
INSERT INTO USER (id,username,birthday,sex,address)
VALUES(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
#{}
和${}
#{}
表示占位符?
,#{}
接收简单类型的参数时,里面的名称可以任意;
${}
表示拼接符,${}
接收简单类型的参数时,里边的名称必须时value;
${}
里面的值会原样输出,不加解析(例如:如果该参数值是字符串,则不会添加引号);
${}
存在sql注入的风险,但是有些场景下必须使用,例如排序后面会动态传人排序的列名。
parameterType和resultType
parameterType
指定输入参数 的java类型,parameterType
只有一个,也就是说传入参数只能有一个。
resultType
指定输出结果的java类型,如果返回的是集合,则指单条记录的java类型。
selectOne和selectList
selectOne
查询单个对象;selectList
查询集合对象。
开发Dao的方式
SqlSessionFactory,它的生命周期,应该在应用范围,全局范围只有一个工厂,使用单例模式来实现这个功能。与spring集成之后,由spring来对其进行单例管理。
SqlSession内部含有一块数据区域,存在线程不安全问题,所以应该将sqlSession声明到方法内部。
原始dao的开发方式
即开发dao接口和dao实现类
Mapper代理的开发方式
即开发mapper接口(就是Dao接口);
Mapper代理使用的是JDK的代理策略。
mapper代理的开发规范
- mapper接口的全限定名要和mapper映射文件的namespace值一致;
- mapper接口的方法名要和mapper映射文件的statement(sql)的id一致;
- mapper接口的方法参数类型和mapper映射文件的statement(sql)的paramterType一致;
- mapper接口的返回值类型要和mapper映射文件的statement(sql)的resultType一致。
mapper映射文件
在config下创建mapper目录,然后创建UserMapper.xml(这是mybatis的命名规范,当然,也不是必须使用这个名称)。
具体使用
@Test
public void testFindUserById() throws Exception {
// 1. 获取session会话
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2. mybatis创建mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 3. 调用接口
User user = mapper.findUserById(1);
System.out.println(user);
// 4. 关闭会话
sqlSession.close();
}
延迟加载
什么是延迟加载
resultMap中的association 和 collection 标签具有延迟加载的功能。
延迟加载的意思是说,在关联查询的时候,利用延迟加载,先加载主信息。按需加载关联信息。这样会大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
设置延迟加载
Mybatis默认是不开启延迟加载功能的,我们需要手动开启。需要在mybatis全局配置文件中的setting
标签中开启延迟加载功能。
<!--开启延迟加载功能 -->
<settings>
<!-- lazyLoadingEnabled:延迟加载启用,默认是false -->
<setting name="lazyLoadingEnabled" value="true" />
<!--aggressiveLazyLoading:积极的懒加载,false表示按需加载,默认是true -->
<setting name="aggressiveLazyLoading" value="false" />
</settings>
Mybatis 的缓存
一级缓存:sqlSession,在sqlSession中又一个数据区域,是map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。
二级缓存:同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。
一级缓存是默认开启的,二级缓存默认关闭。
整合ehcache
Mybatis本身是一个持久层框架,它不是专门的缓存框架,所以它对缓存的实现不够好,它本身不支持分布式缓存。
Ehcache 是一个分布式缓存。
整合思路
Cache是一个接口,它的默认实现是mybatis的PerpetualCache。如果想整合mybatis的二级缓存,那么实现Cache接口即可。
- 添加jar包
- 开启在mybatis总配置文件中,开启二级缓存
<settings>
<!-- 开启二级缓存总开关 -->
<setting name="cacheEnabled" value="true" />
</settings>
- 在mapper文件中添加cache标签
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
- 在config目录下,添加ehcache的配置文件
- 相关的类要实现序列化接口。
mybatis 二级缓存的应用场景
使用场景:对于访问响应速度要求高,但是实时性不高的查询,可以采用二级缓存。
注意:在使用二级缓存的时候,要设置一下刷新间隔(cache标签中有一个flashInterval属性)来定时刷新二级缓存,这个刷新间隔根据具体需求来设置,比如设置30分钟、60分钟等,单位为毫秒。
mybatis二级缓存的局限性
mybatis二级缓存对细粒度的数据,缓存实现不好。
场景:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次查询都是最新的商品信息,此时如果使用二级缓存,就无法实现当一个商品的属性发生变化时只刷新该商品的缓存信息。因为mybatis的二级缓存是mapper级别的,当一个商品的信息发生更新,所有的商品缓存信息都会被清空。
解决此类问题,需要在业务层根据需求对数据有针对性的缓存。
比如可以对经常变化的数据操作单独放到另一个namespace的mapper中。
分布式
一个tomcat大概支持400个左右的并发访问量。
负载均衡,ngnix做负载均衡。
ngnix负载均衡,软负载的策略,硬负载策略。
对缓存进行
为了高可用,高并发。
带宽有限制,100M已经很大了。带宽优化来解决高并发。
- 应用服务器做一些负载,根据并发数去线性扩展。
- 数据库是影响高并发的关键部分。数据库读写分离可以提高性能,读写数据库之间有一个同步机制。
- 互联网应用必须做三个测试:功能测试、性能测试、安全测试。