設計目標
Service→緩衝→資料庫
初次查詢資料來自資料庫,重新查詢來自緩衝
有增刪改,令緩衝失效 項目結構
主要關註:service、jpadao、entity幾個源碼包和測試包
設定檔在resources下的-jpa檔案和cache目錄下的-redis檔案
建表語句在\showcase\src\test\resources\init-table-user.sql
日誌配置在\showcase\src\test\resources\logback-test.xml Spring Data JPA 完成Dao的編寫 依賴管理
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.11.7.RELEASE</version></dependency><!-- hibernate jpa--><dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.7.Final</version></dependency><dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>2.2.4</version></dependency>
當然還有其他依賴,如下面要用到的h2資料庫,spring的context等,讀者運行測試案例時缺什麼包再依賴什麼包吧。 實體類 org.lanqiao.showcase.entity.User
@Entity@Table(name = "t_user")public class User implements Serializable{ private Integer id; private String username; private String password; private Integer status; private Integer teamId; @Id @GeneratedValue(strategy =GenerationType.AUTO) public Integer getId() { return id; } @Column(name="team_id") public Integer getTeamId() { return teamId; } // 其餘略
sql:init-table-user.sql
CREATE TABLE IF NOT EXISTS t_user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(100), password VARCHAR(100), status INT, team_id INT, PRIMARY KEY (`id`));INSERT INTO t_user (username, password, status,team_id) VALUES ('aaa','aaa',1,1);INSERT INTO t_user (username, password, status,team_id) VALUES ('bbb','aaa',1,1);INSERT INTO t_user (username, password, status,team_id) VALUES ('ccc','aaa',1,2);INSERT INTO t_user (username, password, status,team_id) VALUES ('ddd','aaa',1,2);CREATE TABLE t_team( id INT AUTO_INCREMENT, name VARCHAR(100), PRIMARY KEY (`id`));INSERT INTO t_team (name) VALUES ('蒙特內格羅老妖');INSERT INTO t_team (name) VALUES ('天山童母');
spring xml applicationContext-jpa.xml
<!-- Jpa Entity Manager 配置 entityManager是crud的API--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/> <!--掃描實體@Entity--> <property name="packagesToScan" value="org.lanqiao.showcase.entity"/> <property name="jpaProperties"> <props> <!-- 命名規則 My_NAME->MyName --> <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> </props> </property> </bean> <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <!--設定方言--> <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect"/> </bean> <!-- Spring Data Jpa配置 尋找和裝配DAO--> <jpa:repositories base-package="org.lanqiao.showcase.jpadao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/> <!-- Jpa 事務配置 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- 使用annotation定義事務 --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> <jdbc:embedded-database id="dataSource" type="H2"> <jdbc:script location="classpath:init-table-user.sql"/> </jdbc:embedded-database> <bean id="userService" class="org.lanqiao.showcase.service.UserService"/>
DAO的編寫 org.lanqiao.showcase.jpadao.UserDao
import org.lanqiao.showcase.entity.User;import org.springframework.data.repository.CrudRepository;public interface UserDao extends CrudRepository<User,Integer> {}
單元測試 org.lanqiao.showcase.jpadao.UserDaoTest
package org.lanqiao.showcase.jpadao;import org.lanqiao.showcase.entity.User;import org.junit.Before;import org.junit.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;import org.web2017.test.data.RandomData;import static org.assertj.core.api.Assertions.assertThat;@ContextConfiguration("classpath:applicationContext-jpa.xml")public class UserDaoTest extends AbstractTransactionalJUnit4SpringContextTests { @Autowired private UserDao userDao; @Test public void testFindAll() { save(); // 初始化4條,上面又增一條 assertThat(userDao.findAll().iterator()).hasSize(5); } private void save(){ final User entity = new User(); entity.setUsername(RandomData.randomName("username")); entity.setPassword(RandomData.randomName("password")); userDao.save(entity); }}
順便貼下logback-test.xml(test/resources目錄下)
用來查看sql列印:
<?xml version="1.0" encoding="UTF-8"?><configuration> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>/tmp/logs/fullstack.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>/tmp/logs/fullstack.%d{yyyy-MM-dd}.log </fileNamePattern> </rollingPolicy> <encoder> <pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <!-- project default level --> <logger name="org.lanqiao" level="debug" /> <logger name="org.web2017" level="debug" /> <logger name="org.hibernate.SQL" level="debug"/> <root level="warn"> <appender-ref ref="console"/> <!-- 生產環境取消下行注釋 <appender-ref ref="rollingFile" level="error"/> --> </root></configuration>
主要是這一行<logger name="org.hibernate.SQL" level="debug"/> 小結
單元測試能跑通,說明持久層資料庫的訪問是沒有問題的 Spring Cache整合Redis完成服務層緩衝 redis串連資訊 cache/redis-config.properties
# Redis settings# server IPredis.host=your_redis_ip# server portredis.port=63799# server passredis.pass=your_redis_secret# use dbIndexredis.database=0# 控制一個pool最多有多少個狀態為idle(閒置)的jedis執行個體redis.maxIdle=300# 表示當borrow(引入)一個jedis執行個體時,最大的等待時間,如果超過等待時間(毫秒),則直接拋出JedisConnectionException;redis.maxWait=3000# 在borrow一個jedis執行個體時,是否提前進行validate操作;如果為true,則得到的jedis執行個體均是可用的redis.testOnBorrow=true
配置redisCacheManager並開啟cache註解驅動:cache/applicationContext-redis.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:cache/redis-config.properties"/> <!-- 啟用緩衝註解功能,這個是必須的,否則註解不會生效,另外,該註解一定要聲明在spring主設定檔中才會生效 --> <cache:annotation-driven cache-manager="redisCacheManager"/> <!-- redis 相關配置 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}"/> <property name="maxWaitMillis" value="${redis.maxWait}"/> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> </bean> <bean id="JedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="JedisConnectionFactory"/> <property name="keySerializer" > <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="valueSerializer" > <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> </bean> <!-- spring自己的緩衝管理器,這裡定義了緩衝位置名稱 ,即註解中的value --> <bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager" c:redisOperations-ref="redisTemplate" p:usePrefix="true" > <property name="cacheNames"> <list> <value>userCache</value> <value>teamCache</value> </list> </property> <property name="cachePrefix"> <bean class="org.springframework.data.redis.cache.DefaultRedisCachePrefix"/> </property> </bean></beans>
這個網上都找得到,需要說明的是:redisTemplate中為了便於到redis伺服器去查驗資料,最好將key的序列化設定為字串序列化:
<property name="keySerializer" > <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property>
value序列化用JDK內建對象序列化,所以要求我們的實體類實現Serializable介面 編寫Service完成簡單邏輯並使用Spring @Cache×××註解:
package org.lanqiao.showcase.service;import org.lanqiao.showcase.entity.User;import org.lanqiao.showcase.jpadao.UserDao;import org.springframework.beans.factory