整理不易,不喜勿喷。谢谢
SpringBoot — 整合Ldap.
SpringBoot — 整合Spring Data JPA.
SpringBoot — 整合Elasticsearch.
SpringBoot — 整合spring-data-jpa和spring-data-elasticsearch.
SpringBoot — 整合thymeleaf.
SpringBoot — 注入第三方jar包.
SpringBoot — 整合Redis.
Springboot — 整合slf4j打印日志.
Springboot — 整合定时任务,自动执行方法.
Springboot — 配置多数据源,使用JdbcTemplate以及NamedParameterJdbcTemplate.
Sprignboot — 详解pom.xml中build和profile.
SpringBoot — 监控.
SpringBoot — 缓存Cache/Redis.
SpringBoot与Zookeeper.
Git的使用.
Repository:是Spring Data的核心概念,抽象了对数据库和Nosql的操作
接口如下:
- Repository
- CrudRepository 提供了基础的增删改查,批量操作接口
- JpaRepository 提供了更丰富的数据库访问接口
- PagingAndSortingReposlitory 集成CrudRepository,附加了分页查询功能
- JPASpecificationExecutor接口
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
server.port=8083
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.jdbc-url=jdbc:oracle:thin:@//10.xxx.14:1521/Pxxxxx
spring.datasource.username=study123456
spring.datasource.password=study123456
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean(name = "dataSource1")
@Qualifier("dataSource1")
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource1(){
return DataSourceBuilder.create().build();
}
}
GenerationType四中类型:
- TABLE:使用一个特定的数据库表格来保存主键。
- SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
- IDENTITY:主键由数据库自动生成(主要是自动增长型)
- AUTO:主键由程序控制。
@Data
@Entity
@Table(name = "USERS")
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
//@GeneratedValue(strategy = GenerationType.IDENTITY) 主键自增
@Column(name = "id")
private int id;
@Column
private String username;
@Column
private String password;
@Column
private int age;
}
要严格遵守命名规则,findBy + 某个字段
常用关键字如下:
-and
And 例如:findByUsernameAndPassword(String user, Striang pwd);
-or
Or 例如:findByUsernameOrAddress(String user, String addr);
-between
Between 例如:SalaryBetween(int max, int min);
-"<"
LessThan 例如: findBySalaryLessThan(int max);
-">"
GreaterThan 例如: findBySalaryGreaterThan(int min);
-is null
IsNull 例如: findByUsernameIsNull();
-is not null
IsNotNull NotNull 与 IsNotNull 等价 例如: findByUsernameIsNotNull();
-like
Like 例如: findByUsernameLike(String user);
-not like
NotLike 例如: findByUsernameNotLike(String user);
-order by
OrderBy 例如: findByUsernameOrderByNameAsc(String user);直接通过name正序排序
-"!="
Not 例如: findByUsernameNot(String user);
-in
In 例如: findByUsernameIn(Collection userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
-not in
NotIn 例如: findByUsernameNotIn(Collection userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
-Top/Limit
查询方法结果的数量可以通过关键字来限制,first 或者 top都可以使用。top/first加数字可以指定要返回最大结果的大小 默认为1
import org.springframework.data.repository.Repository;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public interface UserRepository extends Repository<Users,Integer> {
//方法名称必须要遵循驼峰式命名规则,findBy(关键字)+属性名称(首字母大写)+查询条件(首字母大写)
List<Users> findByUsername(String name);
List<Users> findByUsernameAndAge(String name,int age);
List<Users> findByUsernameLike(String name);
}
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
@Component
public interface UserRepository extends CrudRepository<Users,Integer> {
}
@Autowired
UserRepository userRepository;
@Test
void test4() {
Users users = new Users();
users.setId(5);
users.setUsername("leon");
users.setPassword("123");
users.setAge(18);
userRepository.save(users);
}
@Test
void test5() {
Iterable<Users> all = userRepository.findAll();
for (Users users : all) {
System.out.println(users);
}
}
@Test
void test6() {
Optional<Users> byId = userRepository.findById(1);
System.out.println(byId);
}
CrudRepository的方法如下
S save(S var1);
Iterable saveAll(Iterable var1);
Optional findById(ID var1);
boolean existsById(ID var1);
Iterable findAll();
Iterable findAllById(Iterable var1);
long count();
void deleteById(ID var1);
void delete(T var1);
void deleteAll(Iterable var1);
void deleteAll();
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public interface UserRepository extends PagingAndSortingRepository<Users,Integer> {
}
注意:API变更
Sort sort=Sort.by(new Sort.Order(Sort.Direction.DESC,“id”));
Pageable pageable = PageRequest.of(int page, int size, Sort sort);
@Autowired
UserRepository userRepository;
@Test
void test() {
//Pageable:封装了分页的参数,当前页,煤业显示的条数。注意:它的当前页是从0开始
//PageRequest(page,size):page表示当前页,size表示每页显示多少条
Sort sort=Sort.by(new Sort.Order(Sort.Direction.DESC,"id"));
Pageable pageable=PageRequest.of(1,2,sort);
Page<Users> all = userRepository.findAll(pageable);
System.out.println("数据的总条数:"+all.getTotalElements());
System.out.println("总页数:"+all.getTotalPages());
List<Users> list=all.getContent();
for (Users users:list){
System.out.println(users);
}
}
- 两种传参的方式
- select只能选一个字段
- update、delete要加@Modifying,并且方法加上事务@Transictional
import com.example.jpa.entity.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
public interface UserRepository extends JpaRepository<Users,Integer> {
/**
* 可以重写
*/
@Override
Optional<Users> findById(Integer integer);
/**
* 对于复杂查询,可以自己写sql语句。自己写sql语句时,方法名不需要遵守规范
* 但表名要换成实体类名,字段名要换成员变量名
*/
@Query("select user from Users user where user.username=?1 and user.password=?2")
List<Users> findAllByUsernameAndPassword(String username, String password);
@Query("select user from Users user where user.username=:username and user.password=:password")
List<Users> findAllByUsernameAndPassword2(@Param("username") String username, @Param("password") String password);
/**
* 可以select user.xxx选中一个字段,方法返回写该字段的类型或者该类型的List
* 也可以select user选中全部字段,方法返回写实体类或者实体类的List
* 要取多个字段时,直接select user取全部字段
* 也不能select user.*使用*号
*/
@Query("select user.age from Users user where user.username=:username and user.password=:password")
List<String> findAllByUsernameAndPassword3(@Param("username") String username, @Param("password") String password);
/**
* 写update、delete语句时,需要加 @Modifying
* 调用时不管调用几个dao层的方法,只要调用了update|delete,都必须要在方法上加事务 @Transactional
* 加spring的事务、javax的事务均可
*/
@Modifying
@Query("update Users user set user.username=:username,user.password=:password where user.id=:id")
int updateUsernameAndPassword(@Param("id") Integer id, @Param("username") String username, @Param("password") String password);
}
//源码方法如下:
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
<S extends T> List<S> saveAll(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
Spring Data JPA支持Criteria查询,可以很方便地使用,足以应付工作中的所有复杂查询的情况
使用Specification的要点就是CriteriaBuilder
package org.springframework.data.jpa.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
public interface JpaSpecificationExecutor<T> {
Optional<T> findOne(@Nullable Specification<T> spec);
List<T> findAll(@Nullable Specification<T> spec);
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
long count(@Nullable Specification<T> spec);
}
Demo:简单查询
@Autowired
StudentSpecificationRepository studentSpecificationRepository;
@Test
void test() {
List<Student> stus = studentSpecificationRepository.findAll(new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//root.get("address")表示获取address这个字段名称,like表示执行like查询,%zt%表示值
Predicate p1 = criteriaBuilder.like(root.get("address"), "%zt%");
Predicate p2 = criteriaBuilder.greaterThan(root.get("id"),3);
//将两个查询条件联合起来之后返回Predicate对象
return criteriaBuilder.and(p1,p2);
}
});
Assert.assertEquals(2,stus.size());
Assert.assertEquals("oo",stus.get(0).getName());
}
Demo1:多个Specification
@Autowired
StudentSpecificationRepository studentSpecificationRepository;
@Test
void test() {
//第一个Specification定义了两个or的组合
Specification<Student> s1 = new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Predicate p1 = criteriaBuilder.equal(root.get("id"),"2");
Predicate p2 = criteriaBuilder.equal(root.get("id"),"3");
return criteriaBuilder.or(p1,p2);
}
};
//第二个Specification定义了两个or的组合
Specification<Student> s2 = new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Predicate p1 = criteriaBuilder.like(root.get("address"),"zt%");
Predicate p2 = criteriaBuilder.like(root.get("name"),"foo%");
return criteriaBuilder.or(p1,p2);
}
};
//通过Specifications将两个Specification连接起来,第一个条件加where,第二个是and
List<Student> stus = studentSpecificationRepository.findAll(Specifications.where(s1).and(s2));
Assert.assertEquals(1,stus.size());
Assert.assertEquals(3,stus.get(0).getId());
}
@ManyToMany
作用:用于映射多对多关系
属性:
cascade:配置级联操作。
fetch:配置是否采用延迟加载。
targetEntity:配置目标的实体类。映射多对多的时候不用写。
@JoinTable
作用:针对中间表的配置
属性:
nam:配置中间表的名称
joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段
inverseJoinColumn:中间表的外键字段关联对方表的主键字段
@JoinColumn
作用:用于定义主键字段和外键字段的对应关系。
属性:
name:指定外键字段的名称
referencedColumnName:指定关联表的主键字段名称
unique:是否唯一。默认值不唯一
nullable:是否允许为空。默认值允许。
insertable:是否允许插入。默认值允许。
updatable:是否允许更新。默认值允许。
columnDefinition:列的定义信息。
@Entity
@Data
public class User implements Serializable {
@Id
@GeneratedValue
private Integer id;
private String username;
private String password;
private String tel;
private String address;
@OneToOne
@JoinColumn(name = "card_id") //指定该实体类对应的外键
private Card card;
}
@Data
@Entity
public class Card implements Serializable {
@Id
@GeneratedValue
private Integer id;
private BigDecimal money;
@OneToOne
@JoinColumn(name = "user_id") //此处可不要@JoinColumn
@JsonIgnore //放弃维护此字段
private User user;
}
员工employee和部门deptment
- JPA使用@OneToMany和@ManyToOne来标识一对多的双向关联。
- 一端(Department )使用 @OneToMany 。
- 多端(Employee )使用 @ManyToOne。
- 在JPA规范中,一对多的双向关系由多端(Employee )来维护。就是说多端(Employee )为关系维护端,负责关系的增删改查。一端(Department )则为关系被维护端,不能维护关系。
- 一端(Department) 使用 @OneToMany 注释的mappedBy="xxxxx"属性表明Department 是关系被维护端。
@Entity
@Data
public class User implements Serializable {
@Id
@GeneratedValue
private Integer id;
private String username;
private String password;
private String tel;
private String address;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY) //mappedBy=当前实体类对应的表
private List<Order> orderList;
}
@Data
@Entity
@Table(name = "tb_order") //order和sql的排序关键字order冲突,不能使用order作为表名
public class Order implements Serializable {
@Id
@GeneratedValue
private Integer id;
@ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
@JoinColumn(name = "user_id") //在多的一方指定外键
@JsonIgnore //放弃维护此字段
private User user;
}
@Data
@Entity
@Table(name = "sys_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long userId;
@Column(name = "user_name")
private String userName;
@Column(name="age")
private Integer age;
/**
* 配置用户到角色的多对多
* 配置多对多的映射关系
* 1.声明表关系的配置
* @ManyToMany(targetEntity = Role.class)//声明多对多
* targetEntity:代表对方实体类字节码
* 2.配置中间表(包含两个外键)
* @JoinTable
* name:中间表的名称
* joinColumns:配置当前对象在中间表的外键
* 接收@inverseJoinColumns数组 name外键名 referencedColumnName:参照的主表主键名
* inverseJoinColumns:配置对方对象在中间表的外键
* 接收@inverseJoinColumns数组 name外键名 referencedColumnName:参照的主表主键名
* @return
*/
@ManyToMany(targetEntity = Role.class)
@JoinTable(name = "sys_user_role",
//joinColumns:当前对象在中间表中的外键 referencedColumnName 来源
joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
//inverseJoinColumns:对方对象在中间表中的外键
inverseJoinColumns ={@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")} )
private Set<Role> roles=new HashSet<Role>();
}
在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的2个字段又作为联合主键,所以报错,主键重复,解决保存失败的问题:只需要在任意一方放弃对中间表的维护权即可,推荐在被动的一方放弃
@Data
@Entity
@Table(name ="sys_role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private Long roleId;
@Column(name = "role_name")
private String roleName;
//配置多对多 放弃维护
@ManyToMany(mappedBy = "roles")//配置
private Set<User> users=new HashSet<User>();
}
//cascade:配置级联操作 All级联所有操作
@OneToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
注意: cascade = CascadeType.ALL 只能写在 One 端,只有One端改变Many端,不准Many端改变One端。
比如 文章和评论,文章是One,评论是Many,如果删除一条评论,就把文章删了。
@Test
@Transactional
@Rollback(value = false)
public void testCasCadeAdd(){
User user=new User();
user.setUserName("小张");
Role role=new Role();
role.setRoleName("程序猿");
user.getRoles().add(role);//配置用户到角色关系,可以对中间表中的数据进行维护
role.getUsers().add(user);//配置角色到用户的关系,可以对中间表的数据进行维护
userDao.save(user);
//查询一号用户
User one = userDao.findOne(1l);
//删除一号用户
userDao.delete(one);
}
@Test
@Transactional //解决java代码中的no session问题
@Rollback(value = false)
public void query() {
//查询id为一的客户
Customer customer = customerDao.getOne(1l);
//对象导航查询,此客户下的所有联系人
Set<LinkMan> linkMans = customer.getLinkMans();
for (LinkMan linkMan : linkMans) {
System.out.println(linkMan);
}
}