MyBatis(七):MyBatis缓存详解(一级缓存/二级缓存)
一级缓存
 MyBatis一级缓存上SqlSession缓存,即在统一SqlSession中,在不执行增删改操作提交事务的前提下,对同一条数据进行多次查询时,第一次查询从数据库中查询,完成后会存入缓存,其余从缓存中直接读取。MyBatis一级缓存默认开启。

二级缓存
 MyBatis二级缓存是命名空间NameSpace缓存,也可理解为二级缓存被多个SqlSession共享,是一个全局变量。
 二级缓存默认是关闭的,需要手动配置进行开启。开启二级缓存后,数据查询流程为:二级缓存->一级缓存->数据库。
二级缓存开启
实体类需要实现Serializable接口
核心配置文件增加标签
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
- 在需要开启的mapper中添加标签
 
<!--开启二级缓存-->
<cache/>
eviction属性可以设置缓存回收策略,默认LRU策略LRU- 最近最少回收,移除最长时间不被使用的对象FIFO- 先进先出,按照缓存进入的顺序来移除它们SOFT- 软引用,移除基于垃圾回收器状态和软引用规则的对象WEAK- 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
flushinterval缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值readOnly: 是否只读;false读写(默认):MyBatis 觉得数据可能会被修改
true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。
size: 缓存存放多少个元素type: 指定自定义缓存的全类名(实现Cache 接口即可)blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。例如:
<cache eviction="LRU" flushInterval="1000*60*60*24*7" readOnly="true" blocking="false" type="MyCache" size="1000"/>
二级缓存测试,多个SqlSession
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); User param = new User();
param.setId(1); SqlSession sqlSession1 = sqlSessionFactory.openSession();
IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = userDao1.findOne(param);
System.out.println(user1);
sqlSession1.close(); SqlSession sqlSession2 = sqlSessionFactory.openSession();
IUserDao userDao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = userDao2.findOne(param);
System.out.println(user2);
sqlSession2.close();
控制台查看输出日志,发现缓存已命中—Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.5
14:26:48,608 DEBUG IUserDao:62 - Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.0
14:26:48,611 DEBUG JdbcTransaction:137 - Opening JDBC Connection
14:26:48,952 DEBUG PooledDataSource:406 - Created connection 543846639.
14:26:48,952 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
14:26:48,957 DEBUG findOne:159 - ==> Preparing: select * from user where id=?
14:26:48,980 DEBUG findOne:159 - ==> Parameters: 1(Integer)
14:26:49,004 DEBUG findOne:159 - <== Total: 1
com.rangers.entity.User{id=1, name='rangers', address='杭州'}
14:26:49,007 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
14:26:49,010 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
14:26:49,011 DEBUG PooledDataSource:363 - Returned connection 543846639 to pool.
14:26:49,014 DEBUG IUserDao:62 - Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.5
com.rangers.entity.User{id=1, name='rangers', address='杭州'}
二级缓存失效条件
首次SqlSession未提交事务时,二级缓存无法命中
SqlSession未提交时,执行结果未放入二级缓存中,这时候第二个SqlSession在查询时候是无法命中的
例如:调整sqlSession1.close();在sqlSession2执行之后,就不会命中缓存
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); User param = new User();
param.setId(1); SqlSession sqlSession1 = sqlSessionFactory.openSession();
IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = userDao1.findOne(param);
System.out.println(user1); SqlSession sqlSession2 = sqlSessionFactory.openSession();
IUserDao userDao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = userDao2.findOne(param);
System.out.println(user2); sqlSession1.close();
sqlSession2.close();
查看控制台输出,发现两次缓存命中都是0.0,Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.0
14:49:39,073 DEBUG IUserDao:62 - Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.0
14:49:39,075 DEBUG JdbcTransaction:137 - Opening JDBC Connection
14:49:39,385 DEBUG PooledDataSource:406 - Created connection 543846639.
14:49:39,385 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
14:49:39,389 DEBUG findOne:159 - ==> Preparing: select * from user where id=?
14:49:39,408 DEBUG findOne:159 - ==> Parameters: 1(Integer)
14:49:39,433 DEBUG findOne:159 - <== Total: 1
com.rangers.entity.User{id=1, name='rangers', address='杭州'}
14:49:39,434 DEBUG IUserDao:62 - Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.0
14:49:39,434 DEBUG JdbcTransaction:137 - Opening JDBC Connection
14:49:39,489 DEBUG PooledDataSource:406 - Created connection 2079179914.
14:49:39,489 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7bedc48a]
14:49:39,491 DEBUG findOne:159 - ==> Preparing: select * from user where id=?
14:49:39,492 DEBUG findOne:159 - ==> Parameters: 1(Integer)
14:49:39,495 DEBUG findOne:159 - <== Total: 1
com.rangers.entity.User{id=1, name='rangers', address='杭州'}
14:49:39,497 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
14:49:39,499 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
14:49:39,500 DEBUG PooledDataSource:363 - Returned connection 543846639 to pool.
14:49:39,500 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7bedc48a]
14:49:39,502 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7bedc48a]
14:49:39,502 DEBUG PooledDataSource:363 - Returned connection 2079179914 to pool.
更新提交事务,与一级缓存一样,增删改操作提交事务会清空缓存
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); User param = new User();
param.setId(1); SqlSession sqlSession1 = sqlSessionFactory.openSession();
IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = userDao1.findOne(param);
System.out.println("sqlSession1查询结果:"+user1);
sqlSession1.close(); SqlSession sqlSession2 = sqlSessionFactory.openSession();
IUserDao userDao2 = sqlSession2.getMapper(IUserDao.class);
param.setName("游骑兵");
param.setAddress("西安");
Boolean flag = userDao2.updateUser(param) > 0;
System.out.println("执行更新操作结果:"+flag);
sqlSession2.commit();
sqlSession2.close(); SqlSession sqlSession3 = sqlSessionFactory.openSession();
IUserDao userDao3 = sqlSession3.getMapper(IUserDao.class);
User user3 = userDao3.findOne(param);
sqlSession3.close();
System.out.println("sqlSession3查询结果:"+user3);
查看控制台输出,经过sqlSession2提交事务后,sqlSession3的查询缓存命中率为0.0
15:00:33,901 DEBUG IUserDao:62 - Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.0
15:00:33,904 DEBUG JdbcTransaction:137 - Opening JDBC Connection
15:00:34,263 DEBUG PooledDataSource:406 - Created connection 543846639.
15:00:34,263 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,267 DEBUG findOne:159 - ==> Preparing: select * from user where id=?
15:00:34,290 DEBUG findOne:159 - ==> Parameters: 1(Integer)
15:00:34,314 DEBUG findOne:159 - <== Total: 1
sqlSession1查询结果:com.rangers.entity.User{id=1, name='rangers', address='杭州'}
15:00:34,317 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,321 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,321 DEBUG PooledDataSource:363 - Returned connection 543846639 to pool.
15:00:34,321 DEBUG JdbcTransaction:137 - Opening JDBC Connection
15:00:34,322 DEBUG PooledDataSource:398 - Checked out connection 543846639 from pool.
15:00:34,322 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,325 DEBUG updateUser:159 - ==> Preparing: update user set name=?,address=? where id=?
15:00:34,325 DEBUG updateUser:159 - ==> Parameters: 游骑兵(String), 西安(String), 1(Integer)
15:00:34,334 DEBUG updateUser:159 - <== Updates: 1
执行更新操作结果:true
15:00:34,335 DEBUG JdbcTransaction:70 - Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,445 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,448 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,450 DEBUG PooledDataSource:363 - Returned connection 543846639 to pool.
15:00:34,450 DEBUG IUserDao:62 - Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.0
15:00:34,450 DEBUG JdbcTransaction:137 - Opening JDBC Connection
15:00:34,451 DEBUG PooledDataSource:398 - Checked out connection 543846639 from pool.
15:00:34,451 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,453 DEBUG findOne:159 - ==> Preparing: select * from user where id=?
15:00:34,454 DEBUG findOne:159 - ==> Parameters: 1(Integer)
15:00:34,458 DEBUG findOne:159 - <== Total: 1
15:00:34,458 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,461 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@206a70ef]
15:00:34,462 DEBUG PooledDataSource:363 - Returned connection 543846639 to pool.
sqlSession3查询结果:com.rangers.entity.User{id=1, name='游骑兵', address='西安'}
多表操作时,对MyBatis二级缓存的影响
- 问题:未同一namespace下进行增删改提交操作时,其他namespace的缓存是无法感知的
 
例如:两个Mapper文件,AMapper.xml和BMapper.xml,B修改了user表中的内容,A是感知不到的,那么再从A里查询如果用到了缓存,就是旧的数据。
 新增UserMapper1.xml ,修改命名空间为com.rangers.dao.IUserDao1
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); User param = new User();
param.setId(1); SqlSession sqlSession1 = sqlSessionFactory.openSession();
IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = userDao1.findOne(param);
System.out.println("sqlSession1查询结果:"+user1);
sqlSession1.close(); SqlSession sqlSession2 = sqlSessionFactory.openSession();
param.setName("游骑兵");
param.setAddress("西安");
Boolean flag = sqlSession2.update("com.rangers.dao.IUserDao1.updateUser",param) > 0;
System.out.println("执行更新操作结果:"+flag);
sqlSession2.commit();
sqlSession2.close(); SqlSession sqlSession3 = sqlSessionFactory.openSession();
IUserDao userDao3 = sqlSession3.getMapper(IUserDao.class);
User user3 = userDao3.findOne(param);
sqlSession3.close();
System.out.println("sqlSession3查询结果:"+user3);
 查看控制台输出,发现sqlSession2成功更新用户信息后,sqlSession3进行查询时二级缓存命中,依旧是sqlSession1中的结果,查询结果错误
15:33:54,792 DEBUG JdbcTransaction:137 - Opening JDBC Connection
15:33:55,164 DEBUG PooledDataSource:406 - Created connection 1165303897.
15:33:55,165 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:33:55,168 DEBUG findOne:159 - ==> Preparing: select * from user where id=?
15:33:55,186 DEBUG findOne:159 - ==> Parameters: 1(Integer)
15:33:55,212 DEBUG findOne:159 - <== Total: 1
sqlSession1查询结果:com.rangers.entity.User{id=1, name='Rangers', address='杭州'}
15:33:55,215 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:33:55,218 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:33:55,218 DEBUG PooledDataSource:363 - Returned connection 1165303897 to pool.
15:33:55,219 DEBUG JdbcTransaction:137 - Opening JDBC Connection
15:33:55,220 DEBUG PooledDataSource:398 - Checked out connection 1165303897 from pool.
15:33:55,220 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:33:55,224 DEBUG updateUser:159 - ==> Preparing: update user set name=?,address=? where id=?
15:33:55,225 DEBUG updateUser:159 - ==> Parameters: 游骑兵(String), 西安(String), 1(Integer)
15:33:55,233 DEBUG updateUser:159 - <== Updates: 1
执行更新操作结果:true
15:33:55,233 DEBUG JdbcTransaction:70 - Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:33:55,351 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:33:55,354 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:33:55,355 DEBUG PooledDataSource:363 - Returned connection 1165303897 to pool.
15:33:55,357 DEBUG IUserDao:62 - Cache Hit Ratio [com.rangers.dao.IUserDao]: 0.5
sqlSession3查询结果:com.rangers.entity.User{id=1, name='Rangers', address='杭州'}解决
在查询的Mapper文件中引入cache-ref标签,指向执行增删改操作表的命名空间,例如在UserMapper.xml中增加一下标签
<cache-ref namespace="com.rangers.dao.IUserDao1"/>
在此执行,查看控制台输出,发现第三次查询已直接从数据库中进行查询,结果正确
15:46:05,486 DEBUG IUserDao1:62 - Cache Hit Ratio [com.rangers.dao.IUserDao1]: 0.0
15:46:05,489 DEBUG JdbcTransaction:137 - Opening JDBC Connection
15:46:05,788 DEBUG PooledDataSource:406 - Created connection 1165303897.
15:46:05,789 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,793 DEBUG findOne:159 - ==> Preparing: select * from user where id=?
15:46:05,822 DEBUG findOne:159 - ==> Parameters: 1(Integer)
15:46:05,842 DEBUG findOne:159 - <== Total: 1
sqlSession1查询结果:com.rangers.entity.User{id=1, name='rangers', address='杭州'}
15:46:05,845 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,848 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,848 DEBUG PooledDataSource:363 - Returned connection 1165303897 to pool.
15:46:05,849 DEBUG JdbcTransaction:137 - Opening JDBC Connection
15:46:05,849 DEBUG PooledDataSource:398 - Checked out connection 1165303897 from pool.
15:46:05,849 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,852 DEBUG updateUser:159 - ==> Preparing: update user set name=?,address=? where id=?
15:46:05,852 DEBUG updateUser:159 - ==> Parameters: 游骑兵(String), 西安(String), 1(Integer)
15:46:05,865 DEBUG updateUser:159 - <== Updates: 1
执行更新操作结果:true
15:46:05,865 DEBUG JdbcTransaction:70 - Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,970 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,974 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,976 DEBUG PooledDataSource:363 - Returned connection 1165303897 to pool.
15:46:05,976 DEBUG IUserDao1:62 - Cache Hit Ratio [com.rangers.dao.IUserDao1]: 0.0
15:46:05,976 DEBUG JdbcTransaction:137 - Opening JDBC Connection
15:46:05,976 DEBUG PooledDataSource:398 - Checked out connection 1165303897 from pool.
15:46:05,976 DEBUG JdbcTransaction:101 - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,979 DEBUG findOne:159 - ==> Preparing: select * from user where id=?
15:46:05,979 DEBUG findOne:159 - ==> Parameters: 1(Integer)
15:46:05,985 DEBUG findOne:159 - <== Total: 1
15:46:05,985 DEBUG JdbcTransaction:123 - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,989 DEBUG JdbcTransaction:91 - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45752059]
15:46:05,990 DEBUG PooledDataSource:363 - Returned connection 1165303897 to pool.
sqlSession3查询结果:com.rangers.entity.User{id=1, name='游骑兵', address='西安'}
是否应该使用二级缓存
二级缓存的注意事项:
缓存是以
namespace为单位的,不同namespace下的操作互不影响。insert,update,delete操作会清空所在
namespace下的全部缓存。通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的
namespace。多表操作一定不要使用二级缓存,因为多表操作进行更新操作,一定会产生脏数据。
如果你遵守二级缓存的注意事项,那么你就可以使用二级缓存。
如果不能使用多表操作,二级缓存不就可以用一级缓存来替换掉吗?而且二级缓存是表级缓存,开销大,没有一级缓存直接使用 HashMap 来存储的效率更高,所以二级缓存并不推荐使用。
MyBatis(七):MyBatis缓存详解(一级缓存/二级缓存)的更多相关文章
- 【mybatis源码学习】mybtias一级,二级缓存
		
转载:https://www.cnblogs.com/ysocean/p/7342498.html mybatis 为我们提供了一级缓存和二级缓存,可以通过下图来理解: ①.一级缓存是SqlSessi ...
 - SpringBoot+Mybatis一级缓存和二级缓存详解
		
本文主要介绍在SpringBoot项目中如何使用Mybatis的一级.二级缓存,为了演示方便,本文的数据库采用H2内存数据库,数据库连接池默认使用SpringBoot2.X自带的hikariCP. 正 ...
 - Mybatis一级、二级缓存
		
Mybatis一级.二级缓存 一级缓存 首先做一个测试,创建一个mapper配置文件和mapper接口,我这里用了最简单的查询来演示. <mapper namespace="c ...
 - 170214、mybatis一级和二级缓存
		
mybatis一级缓存是指在内存中开辟一块区域,用来保存用户对数据库的操作信息(sql)和数据库返回的数据,如果下一次用户再执行相同的请求, 那么直接从内存中读数数据而不是从数据库读取. 其中数据的生 ...
 - Hibernate缓存简介和对比、一级缓存、二级缓存详解
		
一.hibernate缓存简介 缓存的范围分为3类: 1.事务范围(单Session即一级缓存) 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象 ...
 - Hibernate一级缓存和二级缓存详解
		
(1)一级缓存 是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么h ...
 - hibernate的一级缓存和二级缓存详解
		
hibernate为我们提供了一级缓存和二级缓存,目的是为了减少应用程序对数据库的访问次数. 一级缓存: (1)所谓一级缓存就是session级别的缓存,当我们使用他的范围是当前的session,当s ...
 - Mybatis SQL映射文件详解
		
Mybatis SQL映射文件详解 mybatis除了有全局配置文件,还有映射文件,在映射文件中可以编写以下的顶级元素标签: cache – 该命名空间的缓存配置. cache-ref – 引用其它命 ...
 - Mybatis系列全解(四):全网最全!Mybatis配置文件XML全貌详解
		
封面:洛小汐 作者:潘潘 做大事和做小事的难度是一样的.两者都会消耗你的时间和精力,所以如果决心做事,就要做大事,要确保你的梦想值得追求,未来的收获可以配得上你的努力. 前言 上一篇文章 <My ...
 
随机推荐
- 【Java】位操作符
			
位运算符 java支持的位运算符有7个,分为两类:位逻辑运算和移位运算.位逻辑运算符包括按位取反(~).按位与(&).按位或(|)和按位异或(^)4种,.移位运算符包括左移(<<) ...
 - Redis 搭建与配置
			
Redis 简介 Redis 是一款开源的,ANSI C 语言编写的,高级键值(Key-Value)缓存和支持永久存储 NoSQL 数据库产品, Redis 采用内存(In-Memory)数据集(Da ...
 - OpenStack Train版-2.安装keystone身份认证服务
			
安装 keystone 认证 mysql -uroot create database keystone; grant all privileges on keystone.* to 'keyston ...
 - 使VS开发的程序在Win7系统运行时自动提升权限
			
软件开发时,总是会遇到在Win7系统上运行不起来或者异常的情况,这通常是用户的权限不够引起的. 下面提供一个可以使程序运行时,自动提升用户权限的方法. 1.右键点击启动项目,单击"属性&qu ...
 - 蓝桥杯-摔手机问题【dp】
			
非常详细的题解:戳这里 例题:poj-3783 Balls Balls Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 115 ...
 - HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解
			
题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...
 - 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(3) - 统一FlexSPI驱动访问
			
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(3)之统一FlexSPI驱动访问. 文接上篇 <超级下载算法(RT-UFL)开发笔记(2) - 识别当前i. ...
 - Github Docs All In One
			
Github Docs All In One docs https://docs.github.com/en https://github.com/github/docs GitHub REST AP ...
 - Python Web Frameworks
			
Python Web Frameworks top 10 Python web frameworks Django (Full-stack framework) Flask (Micro framew ...
 - taro & Error: spawn taro ENOENT
			
taro & Error: spawn taro ENOENT https://stackoverflow.com/questions/27688804/how-do-i-debug-erro ...