spring data 是 spring 解决数据访问 一揽子解决方案,是一个伞形项目
关系型 非关系型 数据访问 解决方案,
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
- spring-data-jpa
- spring-data-mongodb 基于分布式文件存储的数据库
- spring-data-neo4j 是一个高性能的,NOSQL图形数据库,
- spring-data-redis
- spring-data-solr 独立的企业级搜索应用服务器
- spring-data-hadoop
- spring-data-gemfire 分布式缓存GemFire架构
- spring-data-webmvc
- spring-data-oracle
- spring-data-couchbase 分布式的nosql数据库,主要用于分布式缓存和数据存储领域
- spring-data-elasticsearch 是一个基于Lucene的搜索服务器
- spring-data-cassandra 是一套开源分布式NoSQL数据库系统
- spring-data-dynamodb 用来托管的NoSQL数据库服务
用Spring Data Commons项目实现
CRUD 创建 获取 更新 删除 查询 排序 分页
Spring Data Repository 抽象,
他的子接口,CrudRepository 有crud操作
CrudRepository 的子接口,PagingAndSortingRepository定义了分页和排序相关的操作
不同的数据访问 提供了不同的 Repository ,如: JpaRepository 。 MongoDB 有 MongoRepository
public interface PersonRepository extends Repository<Person, Long> {
Long countByAge(Integer age);//按照年龄计数
Long deleteByName(String name);//根据名字删除
List<Person> findByName(String name);//根据名字查询
List<Person> findByNameAndAddress(String name,String address);//根据名字和地址查询
}
docker
轻量级容器技术,类似于虚拟机技术,直接运行在当前操作系统之上,也实现了虚拟机技术的资源隔离。
将软件编译成一个额镜像,使用者运行这个镜像。运行中的镜像称之为容器。
阿里云,百度云,Cloud Foundry (spring家的,最成熟稳定)
云计算平台 一般指的是 PaaS 平台即服务。
平台提供给了存储,数据库,网络,负载均衡,自动扩展等功能。
你只需要把你的程序交给云计算平台即可。
数据库: Oracle XE
Redis作为缓存
NoSql数据库
MongoDB
ActiveMQ,RabbitMQ
curl https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo
yum install https://download.docker.com/linux/fedora/30/x86_64/stable/Packages/containerd.io-1.2.6-3.3.fc30.x86_64.rpm
//docker-ce-cli-19.03.8-3.fc30.x86_64.rpm 最新
yum install docker-ce 报错的话
yum install docker-ce --nobest #看提示,在执行的代码加上--nobest,就可以执行成功
1 systemctl start docker
2 systemctl enable docker
echo { "registry-mirrors": ["http://hub-mirror.c.163.com"] } >>/etc/docker/daemon.json
vi /etc/docker/daemon.json
{
"registry-mirrors": ["http://hub-mirror.c.163.com"]
} //注意查看json的格式是否正确,和 这个配置文件的权限
阿里云
https://pee6w651.mirror.aliyuncs.com
docker pull mysql:5.7
window7 通过 Boot2Ddocker ,包含了一个 virtualBox
window10 应用商店自带
https://hub.docker.com/
docker pull redis
docker images
docker rmi image-id
docker rmi $(docker images -q)
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 4cdbec704e47 45 hours ago 98.2MB
Docker容器命令
docker run --name test-redis -d redis
docker run --name container-name -d image-name
container-name 为容器取得名字
-d detached 执行完这句命令后控制台将不会被阻碍,可继续输入命令操作
image-name 要使用哪个镜像来运行容器
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5551a597ece0 redis "docker-entrypoint.s…" 2 minutes ago
Up 2 minutes 6379/tcp test-redis
command 容器启动时调用的命令
docker ps -a 查看运行和停止状态的容器
docker stop container-name/container-id
docker stop test-redis //停止容器
docker start container-name/container-id
docker start test-reids //开始容器
docker rm test-redis //删除
端口映射
docker 所使用的端口,在本机 和 本机的局域网 是不能访问的。所以要端口映射。
容器中的端口 映射到 当前主机的端口上,
docker run --name test-redis -d redis
docker run -d -p 6378:6379 --name port-redis redis
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e936f9ed930d redis "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 0.0.0.0:6378->6379/tcp port-redis
docker rm container-id
docker rm $(docker ps -a -q)
docker logs container-id/container-name
docker logs port-reids
登录容器:就像进入linux系统
docker exec -it container-id/container-name bash
下载镜像
oracle xe,MongoDB,Redis,ActiveMQRabbit MQ
docker pull wnameless/oracle-xe-11g
mongo
redis:2.8.21 下载失败
cloudesire/activemq
rabbitmq
rabbitmq:3-managemenmt
异常处理:进入VirtualBox。win7 docker
boot2docker ssh
spring Data JPA
JPA 主要实现 Hibernate , EclipseLink OpenJPA
只需要集成JpaRepository
@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAll(Iterable<ID> ids);
<S extends T> List<S> save(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
}
自己写的,及集成 repository
public interface PersonSimpleRepository extends Repository<Person, Long> {
Long countByAge(Integer age);//按照年龄计数
Long deleteByName(String name);//根据名字删除
List<Person> findByName(String name);//根据名字查询
List<Person> findByNameAndAddress(String name, String address);//根据名字和地址查询
}
Spring Data JPA 可通过 @EnableJpaRepositories
查询关键字
And
Or
Is,Equarls
Between
LessThan
LessThanEqual
GreaterThan >
GreaterThanEqual >=
public interface PersonHuaRepository extends JpaRepository<Person, Long> {
List<Person> findFirst10ByNmae(String name);//查询符合条件的前10个
List<Person> findTop10ByNmae(String name);//查询符合条件的前10个
}
例子
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.2.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId> //里面有大量的工具类
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
@SpringBootApplication
//开启自定义的配置
@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
public class Ch82Application {
@Autowired
PersonRepository personRepository;
public static void main(String[] args) {
SpringApplication.run(Ch82Application.class, args);
}
}
application.properties
spring.datasource.driverClassName=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc\:oracle\:thin\:@localhost\:1521\:xe
spring.datasource.username=boot
spring.datasource.password=boot
#1
spring.jpa.hibernate.ddl-auto=update
#2
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true #输出更美观
ddl-auto:create 启动时删除上次生成的表
create-drop:生成表,sessionFactory关闭时候,表删除
update:实体类变动的时候,表结构更新
validate:验证是否一致
none:不采取措施
data.sql
insert into person(id,name,age,address) values(hibernate_sequence.nextval,'xx',31,'北京');
insert into person(id,name,age,address) values(hibernate_sequence.nextval,'yy',30,'上海');
定义映射实体类
@Entity //1 和数据库表映射的实体类
@NamedQuery(name = "Person.withNameAndAddressNamedQuery",
query = "select p from Person p where p.name=?1 and address=?2") //@NamedQuery沙雕
public class Person {
@Id //2主键
@GeneratedValue //3 默认使用主键方式自增
private Long id;
private String name;
private Integer age;
private String address;
//get set 全参 和 无参构造
}
自定义的配置
public class CustomRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable>
extends JpaRepositoryFactoryBean<T, S, ID> {// 1
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {// 2
return new CustomRepositoryFactory(entityManager);
}
private static class CustomRepositoryFactory extends JpaRepositoryFactory {// 3
public CustomRepositoryFactory(EntityManager entityManager) {
super(entityManager);
}
@Override
@SuppressWarnings({"unchecked"})
protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(
RepositoryInformation information, EntityManager entityManager) {// 4
return new CustomRepositoryImpl<T, ID>((Class<T>) information.getDomainType(), entityManager);
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {// 5
return CustomRepositoryImpl.class;
}
}
}
dao
public interface PersonRepository extends CustomRepository<Person, Long> {
List<Person> findByAddress(String address);
List<Person> findByNameLike(String name);
Person findByNameAndAddress(String name,String address);
@Query("select p from Person p where p.name= :name and p.address= :address")
Person withNameAndAddressQuery(@Param("name")String name,@Param("address")String address);
Person withNameAndAddressNamedQuery(String name,String address); //@NamedQuery沙雕
}
//书上集成了 JpaRepository
specs
public class CustomerSpecs {
public static <T> Specification<T> byAuto(final EntityManager entityManager, final T example) { //1
final Class<T> type = (Class<T>) example.getClass();//2
return new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<>(); //3
EntityType<T> entity = entityManager.getMetamodel().entity(type);//4
for (Attribute<T, ?> attr : entity.getDeclaredAttributes()) {//5
Object attrValue = getValue(example, attr); //6
if (attrValue != null) {
if (attr.getJavaType() == String.class) { //7
if (!StringUtils.isEmpty(attrValue)) { //8
predicates.add(cb.like(root.get(attribute(entity, attr.getName(), String.class)),
pattern((String) attrValue))); //9
}
} else {
predicates.add(cb.equal(root.get(attribute(entity, attr.getName(), attrValue.getClass())),
attrValue)); //10
}
}
}
return predicates.isEmpty() ? cb.conjunction() : cb.and(toArray(predicates, Predicate.class));//11
}
/**
* 12
*/
private <T> Object getValue(T example, Attribute<T, ?> attr) {
return ReflectionUtils.getField((Field) attr.getJavaMember(), example);
}
/**
* 13
*/
private <E, T> SingularAttribute<T, E> attribute(EntityType<T> entity, String fieldName,
Class<E> fieldClass) {
return entity.getDeclaredSingularAttribute(fieldName, fieldClass);
}
};
}
/**
* 14
*/
static private String pattern(String str) {
return "%" + str + "%";
}
}
support
自定义配置也放在了此目录下
@NoRepositoryBean
public interface CustomRepository<T, ID extends Serializable>extends JpaRepository<T, ID> ,JpaSpecificationExecutor<T>{
Page<T> findByAuto(T example,Pageable pageable);
}
public class CustomRepositoryImpl <T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements CustomRepository<T,ID> {
private final EntityManager entityManager;
public CustomRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
@Override
public Page<T> findByAuto(T example, Pageable pageable) {
return findAll(byAuto(entityManager, example),pageable);
}
}
web
@RestController
public class DataController {
//1 Spring Data JPA已自动为你注册bean,所以可自动注入
@Autowired
PersonRepository personRepository;
/**
* 保存
* save支持批量保存:<S extends T> Iterable<S> save(Iterable<S> entities);
*
* 删除:
* 删除支持使用id,对象以,批量删除及删除全部:
* void delete(ID id);
* void delete(T entity);
* void delete(Iterable<? extends T> entities);
* void deleteAll();
*
*/
@RequestMapping("/save")
public Person save(String name,String address,Integer age){
Person p = personRepository.save(new Person(null, name, age, address));
return p;
}
/**
* 测试findByAddress
*/
@RequestMapping("/q1")
public List<Person> q1(String address){
List<Person> people = personRepository.findByAddress(address);
return people;
}
/**
* 测试findByNameAndAddress
*/
@RequestMapping("/q2")
public Person q2(String name,String address){
Person people = personRepository.findByNameAndAddress(name, address);
return people;
}
/**
* 测试withNameAndAddressQuery
*/
@RequestMapping("/q3")
public Person q3(String name,String address){
Person p = personRepository.withNameAndAddressQuery(name, address);
return p;
}
/**
* 测试withNameAndAddressNamedQuery
*/
@RequestMapping("/q4")
public Person q4(String name,String address){
Person p = personRepository.withNameAndAddressNamedQuery(name, address);
return p;
}
/**
* 测试排序
*/
@RequestMapping("/sort")
public List<Person> sort(){
List<Person> people = personRepository.findAll(new Sort(Direction.ASC,"age"));
return people;
}
/**
* 测试分页
*/
@RequestMapping("/page")
public Page<Person> page(){
Page<Person> pagePeople = personRepository.findAll(new PageRequest(1, 2));
return pagePeople;
}
@RequestMapping("/auto")
public Page<Person> auto(Person person){
Page<Person> pagePeople = personRepository.findByAuto(person, new PageRequest(0, 10));
return pagePeople;
}
}
oracle xe
是 oracle公司提供的免费开发测试用途的数据库,数据大小限制为4G
docker run -d -p 9090:8080 -p 1512:1512 wnameless/oracle-xe-11g
管理界面的8080,映射为本机的9090
1521 映射为 1521 不变
docker run -d -p 49160:22 -p 49161:1521 wnameless/oracle-xe-11g 可用
hostname: localhost
port: 49161
sid: xe
username: system
password: oracle
SYSTEM和SYS的初始密码都为 oracle
Container SSH 的 root 密码为admin
容器的安装信息
hostname:localhost
端口:1521
sid:xe
username:system/sys
password:oracle
管理界面
url:http://localhost:8080/apex ,用书本,可访问,密码不对
workspace:internal
username:admin
password:oracle
oralce驱动导入
https://www.oracle.com/database/technologies/jdbcdriver-ucp-downloads.html
mvn install:install-file -DgroupId=com.oracle "-DartifactId=ojdbc6" "-Dversion=11.2.0.2.0" "-Dpackaging=jar" "-Dfile=E:\ojdbc6.jar"
-DgroupId
-DartifactId
-Dversion
-Dfile
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.2.0</version>
</dependency>
spring Data Rest实战
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
application.properties与个例子保持一致
spring.datasource.driverClassName=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc\:oracle\:thin\:@192.168.31.183\:49161\:xe
spring.datasource.username=system
spring.datasource.password=oracle
#1
spring.jpa.hibernate.ddl-auto=update
#2
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true
spring.data.rest.base-path= /api # 所以下面要用这个请求开头
debug=true
实体类
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private Integer age;
private String address;
public Person() {
super();
}
public Person(Long id, String name, Integer age, String address) {
super();
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
}
dao
@RepositoryRestResource(path = "people")
public interface PersonRepository extends JpaRepository<Person, Long> {
@RestResource(path = "nameStartsWith", rel = "nameStartsWith")
Person findByNameStartsWith(@Param("name")String name);
}
请求
http://localhost:8080/api/people
{
"_links": {
"self": {
"href": "http://localhost:8080/api/people"
},
"search": {
"href": "http://localhost:8080/api/people/search"
}
},
"_embedded": {
"persons": [
{
"name": "汪云飞",
"age": 32,
"address": "合肥",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/21" #id查询
}
}
},
{
"name": "xx",
"age": 31,
"address": "北京",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/22"
}
}
},
{
"name": "yy",
"age": 30,
"address": "上海",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/23"
}
}
},
{
"name": "zz",
"age": 29,
"address": "南京",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/24"
}
}
},
{
"name": "aa",
"age": 28,
"address": "武汉",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/25"
}
}
},
{
"name": "bb",
"age": 27,
"address": "合肥",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/26"
}
}
},
{
"name": "dd",
"age": 22,
"address": "上海",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/27"
}
}
}
]
},
"page": {
"size": 20,
"totalElements": 7,
"totalPages": 1,
"number": 0
}
}
http://localhost:8080/api/people/search/nameStartsWith?name=汪 //自定义的查询
{
"name": "汪云飞",
"age": 32,
"address": "合肥",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/21"
}
}
}
http://localhost:8080/api/people?page=1&size=2
还给出了上一页,下一页,的资源路径
{
"_links": {
"first": {
"href": "http://localhost:8080/api/people?page=0&size=2"
},
"prev": {
"href": "http://localhost:8080/api/people?page=0&size=2"
},
"self": {
"href": "http://localhost:8080/api/people"
},
"next": {
"href": "http://localhost:8080/api/people?page=2&size=2"
},
"last": {
"href": "http://localhost:8080/api/people?page=3&size=2"
},
"search": {
"href": "http://localhost:8080/api/people/search"
}
},
"_embedded": {
"persons": [
{
"name": "yy",
"age": 30,
"address": "上海",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/23"
}
}
},
{
"name": "zz",
"age": 29,
"address": "南京",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/24"
}
}
}
]
},
"page": {
"size": 2,
"totalElements": 7,
"totalPages": 4,
"number": 1
}
}
http://localhost:8080/api/people/?sort=age,desc
http://localhost:8080/api/people/
json post
{
"name":"张三",
"address":"成都",
"age":22
}
{
"name": "张三",
"age": 22,
"address": "成都",
"_links": {
"self": {
"href": "http://localhost:8080/api/people/28" #id 为 28
}
}
}
http://localhost:8080/api/people/21 put请求,更新
{
"name":"张三伞",
"address":"成都",
"age":22
}
http://localhost:8080/api/people/21 #DELETE 请求删除
默认为:
http:localhost:8080/persons 实体类加s