EE颠覆者 第八章 docker ,boot的数据访问 jpa

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值