Cache
Redis
http://www.cnblogs.com/moonandstar08/p/5149585.html
http://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#cassandra-template.id-handling
org.springframework.data.cassandra.repository.support.SimpleCassandraRepository.delete(T)
public void delete(T entity) {
delete(entityInformation.getId(entity));
}
http://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#cassandra.custom-converters
http://ankushs92.github.io/tutorial/2016/05/03/pagination-with-spring-boot.html
@Embeddable key of a OneToMany Map type property.
@Embeded property
@ElementCollection property
http://www.thoughts-on-java.org/jpa-21-how-to-implement-type-converter/
http://www.cherryshoetech.com/2016/05/jpa-json-serializationdeserialization.html
Create a Converter Class that implements AttributerConverter.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
http://springinpractice.com/2012/05/11/pagination-and-sorting-with-spring-data-jpa
https://www.petrikainulainen.net/spring-data-jpa-tutorial/
https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-seven-pagination/
Page<Todo> findAll(Pageable pageRequest);
http://stackoverflow.com/questions/13135309/how-to-find-out-whether-an-entity-is-detached-in-jpa-hibernate
https://www.foreach.be/blog/spring-cache-annotations-some-tips-tricks
Using @Cacheable combines both looking in the cache and storing the result. Using @CachePut and @CacheEvict annotations gives you more fine-grained control. You can also use the @Caching annotation to combine multiple cache related annotations on a single method. Avoid combining @Cacheable and @CachePut on the same method, as the behavior can be quite confusing. But you can put them to some good use.
Since the version 4.3 the Spring's annotation @Cacheable has the option "sync" (by default set to "false") which, if being set to "true", does exactly that. But, as it's said in the documentation, "sync" option is just a hint and whether it's being supported or not is a matter of implementation. The Ehcache implementation in the spring-context-support module, which under the hood does use Ehcache 2.x, does not support this feature. So, what are the options left (besides the ones with using a proper implementation with support of "sync" feature)? To mark the @Cacheable target method as synchonized? It won't help -- in this case, the concurrent threads looking for the same key in the cache would just encounter a cache-miss in parallel, but then the invocations of the target method would be performed in a synchronized manner and still get the cache filled (and the unwanted task performed) more than once -- this is due to the fact that a cache-miss is happening earlier in the Spring cache facility and the actual target method's invocation is just a consequence of it.
https://www.jianshu.com/p/1becdc376f5d
同时一个事务的多个操作需要在同一个Connection上。事务也往往是在业务逻辑层来控制
Redis
http://www.cnblogs.com/moonandstar08/p/5149585.html
http://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#cassandra-template.id-handling
@PrimaryKey("user_id")
private String userId;
org.springframework.data.cassandra.repository.support.SimpleCassandraRepository.delete(T)
public void delete(T entity) {
delete(entityInformation.getId(entity));
}
@PrimaryKeyColumn(name = "person_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String personId;
@PrimaryKeyColumn(name = "event_code", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
private int eventCode;
@PrimaryKeyColumn(name = "event_time", ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
private Date eventTime;
A primary key class is a composite primary key class that is mapped to multiple fields or properties of the entity. It’s annotated with
@PrimaryKeyClass
and defines equals
and hashCode
methods. The semantics of value equality for these methods should be consistent with the database equality for the database types to which the key is mapped. Primary key classes can be used with Repositories (as the Id type) and to represent an entities' identity in a single complex object.@PrimaryKeyClass
public class LoginEventKey implements Serializable {
@PrimaryKeyColumn(name = "person_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String personId;
@PrimaryKeyColumn(name = "event_code", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
private int eventCode;
@PrimaryKeyColumn(name = "event_time", ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
private Date eventTime;
// other methods omitted for brevity
}
@PrimaryKey
private LoginEventKey key;
http://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#cassandra.custom-converters
static class PersonWriteConverter implements Converter<Person, String> {
public String convert(Person source) {
try {
return new ObjectMapper().writeValueAsString(source);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
@Configuration
public static class Config extends AbstractCassandraConfiguration {
@Override
public CustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
converters.add(new PersonReadConverter());
converters.add(new PersonWriteConverter());
return new CustomConversions(converters);
}
// other methods omitted...
}
http://javabeat.net/introduction-to-spring-converters-and-formatters/28 | GenericConversionService conversionService = new GenericConversionService(); |
29 |
30 | Converter<Article, String> customConverter = new ArticleToStringConverter(); |
31 | conversionService.addConverter(customConverter); |
32 |
33 | Article article = new Article( "Introduction to Spring Converters" , "Core Spring" ); |
34 | String result = conversionService.convert(article, String. class ); |
35 | |
http://ankushs92.github.io/tutorial/2016/05/03/pagination-with-spring-boot.html
@Converter public class ListToStringConveter implements AttributeConverter<List<String>, String> { @Override public String convertToDatabaseColumn(List<String> attribute) { if (attribute == null || attribute.isEmpty()) { return ""; } return StringUtils.join(attribute, ","); } @Override public List<String> convertToEntityAttribute(String dbData) { if (dbData == null || dbData.trim().length() == 0) { return new ArrayList<String>(); } String[] data = dbData.split(","); return Arrays.asList(data); } }
You can use the autoApply attribute of the
Converter
to apply the converter to any supported type.@Converter(autoApply=true) public class ListToStringConveter implements AttributeConverter<List<String>, String> {...}
It is dangerous in a real world project when there are some List you do not want to be converted.
Alternatively, you can apply it on the property via a
@Convert
annotation.@Column(name="TAGS") @Convert(converter = ListToStringConveter.class) private List<String> tags=new ArrayList<>();
You can also place it on class.
@Converts(value={ @Convert(attributeName="tags", converter = ListToStringConveter.class) }) public class Post implements Serializable {...}
When using the specification pattern we move business rules into extra classes called specifications.
em.createQuery( "from User where username = :username", User.class ).setParameter("username", username).getSingleResult();
Querydsl is a framework which enables the construction of statically typed SQL-like queries via its fluent API.
Several Spring Data modules offer integration with Querydsl via
QueryDslPredicateExecutor
.Predicate predicate = user.firstname.equalsIgnoreCase("dave")
.and(user.lastname.startsWithIgnoreCase("mathews"));
userRepository.findAll(predicate);
Query by example is considered exactly what its name suggests: you give an example and the query is built on a match of the given fields.
- Querying your data store with a set of static or dynamic constraints
- Frequent refactoring of the domain objects without worrying about breaking existing queries
- No support for nested/grouped property constraints like
firstname = ?0 or (firstname = ?1 and lastname = ?2)
- Only supports starts/contains/ends/regex matching for strings and exact matching for other property types
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("firstname", endsWith())
.withMatcher("lastname", startsWith().ignoreCase());
}
@Query
(
"SELECT t FROM Todo t where t.title = ?1 AND t.description = ?2"
)
public
Optional<Todo> findByTitleAndDescription(String title, String description);
@Query
(value =
"SELECT * FROM todos t where t.title = ?0 AND t.description = ?1"
,
nativeQuery=
true
)
public
Optional<Todo> findByTitleAndDescription(String title, String description);
@Converter | |
public class ColorConverter implements AttributeConverter<Color, String> |
Create a Converter Class that implements AttributerConverter.
@Convert(converter = JpaJsonDocumentsConverter.class)
private List<JsonDocuments> documents;
@Converter
public class JpaJsonDocumentsConverter implements
AttributeConverter<List<JsonDocuments>, String> {
// ObjectMapper is thread safe
private final static ObjectMapper objectMapper = new ObjectMapper();
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public String convertToDatabaseColumn(List<JsonDocuments> meta) {
String jsonString = "";
try {
log.debug("Start convertToDatabaseColumn");
// convert list of POJO to json
jsonString = objectMapper.writeValueAsString(meta);
log.debug("convertToDatabaseColumn" + jsonString);
} catch (JsonProcessingException ex) {
log.error(ex.getMessage());
}
return jsonString;
}
@Override
public List<JsonDocuments> convertToEntityAttribute(String dbData) {
List<JsonDocuments> list = new ArrayList<JsonDocuments>();
try {
log.debug("Start convertToEntityAttribute");
// convert json to list of POJO
list = Arrays.asList(objectMapper.readValue(dbData,
JsonDocuments[].class));
log.debug("JsonDocumentsConverter.convertToDatabaseColumn" + list);
} catch (IOException ex) {
log.error(ex.getMessage());
}
return list;
}
}
http://stackoverflow.com/questions/24367572/how-to-use-limit-in-spring-within-sql-queryLIMIT
is not part of JPQL. The mechanism available in current release version (1.6.0.RELEASE as of the time of writing) is pagination:interface PersonRepository extends Repository<Person, Long> {
@Query("...")
List<Person> findLimited(..., Pageable pageable);
}
This can then be used as follows:
repository.findLimited(..., new PageRequest(0, 10));
This will return the first ten results of the query defined in the
@Query
annotation.
The current master branch of Spring Data JPA already contains a new feature that would allow you to rewrite above query as follows:
interface PersonRepository extends Repository<Person, Long> {
List<Person> findTop3ByCompanyOrderByName(Company company);
}
As of version 1.7.0.M1 (feature already available in snapshots) the query derivation mechanism will understand
Top
and First
in the subject clause To limit the number of results returned.
The results of query methods can be limited via the keywords
first
or top
, which can be used interchangeably. An optional numeric value can be appended to top/first to specify the maximum result size to be returned. If the number is left out, a result size of 1 is assumed.User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
The limiting expressions also support the
Distinct
keyword. Also, for the queries limiting the result set to one instance, wrapping the result into an Optional
is supported.
The results of query methods can be processed incrementally by using a Java 8
Stream<T>
as return type. Instead of simply wrapping the query results in a Stream
data store specific methods are used to perform the streaming.@Query("select u from User u")
Stream<User> streamAllPaged(Pageable pageable);
@Async
Future<User> findByFirstname(String firstname);
@Async
CompletableFuture<User> findOneByFirstname(String firstname);
@Async
ListenableFuture<User> findOneByLastname(String lastname);
Use java.util.concurrent.Future as return type. | |
Use a Java 8 java.util.concurrent.CompletableFuture as return type. | |
Use a org.springframework.util.concurrent.ListenableFuture as return type |
public Page<Deployment> getDeploymentLog(Integer pageNumber) {
PageRequest request =
new PageRequest(pageNumber - 1, PAGE_SIZE, Sort.Direction.DESC, "startTime");
return deploymentRepo.findAll(pageRequest);
}
http://docs.spring.io/spring-data/jpa/docs/1.8.x/reference/html/#core.webhttps://www.petrikainulainen.net/spring-data-jpa-tutorial/
https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-seven-pagination/
If we want create the Pageable object manually, the service class (or other component) that wants to paginate the query results, which are returned by a Spring Data JPA repository, must create the Pageable object and pass it forward to the invoked repository method.
We have to sort the query results in ascending order by using the values of the title and descriptionfields. If we want to get the second page by using page size 10, we have to create the Pageable object by using the following code:
1
2
3
| private Pageable createPageRequest() { return new PageRequest( 1 , 10 , Sort.Direction.ASC, "title" , "description" ); } |
private Pageable createPageRequest() { return new PageRequest( 1 , 10 , new Sort(Sort.Direction.DESC, "description" ) .and( new Sort(Sort.Direction.ASC, "title" )); ); }
|
@RequestMapping
(value =
"/api/todo/search"
, method = RequestMethod.GET)
public
Page<TodoDTO> findBySearchTerm(
@RequestParam
(
"searchTerm"
) String searchTerm,
Pageable pageRequest) {
return
searchService.findBySearchTerm(searchTerm, pageRequest);
}
http://stackoverflow.com/questions/13135309/how-to-find-out-whether-an-entity-is-detached-in-jpa-hibernate
To find out whether an entity has been detached, we'd need to know whether it was previously managed (i.e. came from the database, e.g. by being persisted or obtained from a
find
operation). Hibernate doesn't provide an "entity state history" so the short answer is there isn't a 100% reliable way of doing this but the following workaround should be sufficient in most cases:public boolean isDetached(Entity entity) {
return entity.id != null // must not be transient
&& !em.contains(entity) // must not be managed now
&& em.find(Entity.class, entity.id) != null; // must not have been removed
}
http://stackoverflow.com/questions/23645091/spring-data-jpa-and-hibernate-detached-entity-passed-to-persist-on-manytomany-re
I had the same problem and solved it by removing the
cascade = CascadeType.PERSIST
.
In your case you use
CascadeType.ALL
, which is equivalent to also using the PERSIST, according to the documentation:Defines the set of cascadable operations that are propagated to the associated entity. The value cascade=ALL is equivalent to cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH}.
It means when you try to save the reservation on
reservationDAO.save(reservation)
it will also try to persist the associated Product object. But this object is not attached to this session. So the error occur.entityManager.merge()
is a good option. It will merge the detached objects in the session. No need to change any cascadeType.https://www.foreach.be/blog/spring-cache-annotations-some-tips-tricks
Using @Cacheable combines both looking in the cache and storing the result. Using @CachePut and @CacheEvict annotations gives you more fine-grained control. You can also use the @Caching annotation to combine multiple cache related annotations on a single method. Avoid combining @Cacheable and @CachePut on the same method, as the behavior can be quite confusing. But you can put them to some good use.
@Caching( put = { @CachePut(value = "userCache", key = "'username:' + #result.username", condition = "#result != null"), @CachePut(value = "userCache", key = "#result.id", condition = "#result != null") } )https://enfernuz.blogspot.com/2016/09/spring-cacheable-annotation-and.html
Since the version 4.3 the Spring's annotation @Cacheable has the option "sync" (by default set to "false") which, if being set to "true", does exactly that. But, as it's said in the documentation, "sync" option is just a hint and whether it's being supported or not is a matter of implementation. The Ehcache implementation in the spring-context-support module, which under the hood does use Ehcache 2.x, does not support this feature. So, what are the options left (besides the ones with using a proper implementation with support of "sync" feature)? To mark the @Cacheable target method as synchonized? It won't help -- in this case, the concurrent threads looking for the same key in the cache would just encounter a cache-miss in parallel, but then the invocations of the target method would be performed in a synchronized manner and still get the cache filled (and the unwanted task performed) more than once -- this is due to the fact that a cache-miss is happening earlier in the Spring cache facility and the actual target method's invocation is just a consequence of it.
https://www.jianshu.com/p/1becdc376f5d
同时一个事务的多个操作需要在同一个Connection上。事务也往往是在业务逻辑层来控制
在Spring中,有时候我们是不是要配置多个数据源DataSource?很显然,Spring需要通过DataSource来得到操作数据库的管道Connection,这有点类似于JNDI查找。
这里通过ConnectionHolder类来完成这个过程,需要思考的是在多线程下,这显然是存在问题的。为避免多线程问题,难道我们采用线程安全的Map,比如ConcurrentHashMap,其实我们真正的目的是什么?是保证一个线程下,一个事务的多个操作拿到的是一个Connection,显然使用ConcurrentHashMap根本无法保证!
SingleThreadConnectionHolder
本来线程不安全的,通过ThreadLocal这么封装一下,立刻就变成了线程的局部变量,不仅仅安全了,还保证了一个线程下面的操作拿到的Connection是同一个对象!这种思想,确实非常巧妙,这也是无锁编程思想的一种方式!