Mybatis

配置文件:
全局配置文件(配置数据源、事务运行时信息)
映射文件(执行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代理的开发规范

  1. mapper接口的全限定名要和mapper映射文件的namespace值一致;
  2. mapper接口的方法名要和mapper映射文件的statement(sql)的id一致;
  3. mapper接口的方法参数类型和mapper映射文件的statement(sql)的paramterType一致;
  4. 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接口即可。

  1. 添加jar包
  2. 开启在mybatis总配置文件中,开启二级缓存
<settings>
        <!-- 开启二级缓存总开关 -->
        <setting name="cacheEnabled" value="true" />
    </settings>
  1. 在mapper文件中添加cache标签
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
  1. 在config目录下,添加ehcache的配置文件
  2. 相关的类要实现序列化接口。

mybatis 二级缓存的应用场景

使用场景:对于访问响应速度要求高,但是实时性不高的查询,可以采用二级缓存。
注意:在使用二级缓存的时候,要设置一下刷新间隔(cache标签中有一个flashInterval属性)来定时刷新二级缓存,这个刷新间隔根据具体需求来设置,比如设置30分钟、60分钟等,单位为毫秒。

mybatis二级缓存的局限性

mybatis二级缓存对细粒度的数据,缓存实现不好。

场景:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次查询都是最新的商品信息,此时如果使用二级缓存,就无法实现当一个商品的属性发生变化时只刷新该商品的缓存信息。因为mybatis的二级缓存是mapper级别的,当一个商品的信息发生更新,所有的商品缓存信息都会被清空。
解决此类问题,需要在业务层根据需求对数据有针对性的缓存。
比如可以对经常变化的数据操作单独放到另一个namespace的mapper中。

分布式
一个tomcat大概支持400个左右的并发访问量。
负载均衡,ngnix做负载均衡。

ngnix负载均衡,软负载的策略,硬负载策略。
对缓存进行
为了高可用,高并发。

带宽有限制,100M已经很大了。带宽优化来解决高并发。

  1. 应用服务器做一些负载,根据并发数去线性扩展。
  2. 数据库是影响高并发的关键部分。数据库读写分离可以提高性能,读写数据库之间有一个同步机制。
  3. 互联网应用必须做三个测试:功能测试、性能测试、安全测试。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容