@toc
SpringBoot与数据访问
JDBC
pom文件导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
yml文件配置数据连接信息
spring:
datasource:
username: root
password: ******
url: jdbc:mysql://localhost:3306/willblog?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.jdbc.Driver
连接测试:
在test文件中进行测试,测试代码如下:
public class DemoApplicationTests {
@Autowired
DataSource dataSource;
@Test
public void contextLoads() throws SQLException {
System.out.println("--test--"+dataSource.getClass());
Connection connection=dataSource.getConnection();
System.out.println("--test--"+connection);
connection.close();
}
}
测试截图:
自动配置原理:
org.springframework.boot.autoconfigure.jdbc:
- DataSourceConfiguration,根据配置创建数据源;
- 数据库操作:SpringBoot自动配置了JDBCTemplate操作数据库;
@Controller
public class HelloController {
@Autowired
JdbcTemplate jdbcTemplate;
@ResponseBody
@GetMapping("/query")
public Map<String,Object> map(){
List<Map<String,Object>> list= jdbcTemplate.queryForList("select * from students");
return list.get(0);
}
SpringBoot整合Druid
pom文件引入依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.8</version>
</dependency>
<!--还需要引入log4j依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
配置使用yml配置看起来简洁清晰;
application.yml
spring:
datasource:
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
#配置获取连接等待超时时间
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
这是配置文件部分,但是关于druid的配置部分暂时还未起作用。所以需要我们编写配置类并将其加入容器中:
创建DruidConfig.java,内容如下:
@Configuration
public class DruidConfig {
//将配置文件中关于druid的配置加入容器中,使其起作用;
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
//配置Druid的监控
//1、配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
Map<String,String> initParams = new HashMap<>();
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");//默认就是允许所有访问
initParams.put("deny","192.168.43.19");
bean.setInitParameters(initParams);
return bean;
}
//2、配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
至此Druid就配置完成了,访问路径localhost:8080/druid
输入在该类中设置的用户名密码进行登录;
SpringBoot整合Mybatis并使用Druid数据源
首先配置Druid数据源如上;
- 数据库建表
SpringBoot在数据库建表方面也非常人性化,这里SpringBoot在1.5x版本和2.0X版本有点细微的差别;- 1.5X版本中将sql文件命名为schema-*.sql并放置在文件类路径下即可,系统在启动主程序时会自动加载该文件并在配置的数据库中创建表:
或者将其放置在其他路径,但要在yml配置文件中配置文件路径,该方法文件名字可随意:
yml配置文件添加配置:
- 1.5X版本中将sql文件命名为schema-*.sql并放置在文件类路径下即可,系统在启动主程序时会自动加载该文件并在配置的数据库中创建表:
spring:
datasource:
... ...
schema:
- classpath:sql/schema-all.sql
- classpath:sql/employee.sql
- 2.0X 的SpringBoot中 则需要在上述基础上在配置文件中加一句配置:
spring:
datasource:
... ...
schema:
- classpath:sql/schema-all.sql
- classpath:sql/employee.sql
initialization-mode: always
配置完成重启服务,就可以看到数据库多了两个表:
使用注解版的mybatis操作数据库
- 首先建一个操作数据库的Mapper接口对应的Bean
以department为例:
/**
* @author :will
* @date :2019/8/10 21:35
* @description:操作数据库的mapper
*/
@Mapper
public interface DepartmentMapper {
@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);
@Delete("delete from department where id=#{id}")
public int deletDeptById(Integer id);
//插入数据时数据值直接使用Bean中的对应名称即可
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);
@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department); }
该接口使用注解可对数据库进行各种操作;
- 创建控制类:
@RestController
public class DeptController {
//Service层,自动注入departmentMapper
@Autowired
DepartmentMapper departmentMapper; //此处id为占位符,用@PathVariable("id")可将参数取出
@GetMapping("/dept/{id}")
public Department getDepatement(@PathVariable("id") Integer id){
return departmentMapper.getDeptById(id);
}
@GetMapping("/dept")
public Department insertDept(Department department){
departmentMapper.insertDept(department);
return department;
}
}
接下来直接在浏览器发送请求进行操作数据库:
添加数据库操作:
因为此处添加时直接返回的是代码当中的department对象而不是从数据库中取出的,所以没有id。若想要插入一条数据并可以直接获取到该数据的自增id时,需要在DepartmentMapper 中的insertDept方法上添加上@Options注解,具体如下:
//keyProperty时指定表中主键id,要与表中字段一致
@Options(useGeneratedKeys = true,keyProperty = "id")
//插入数据时数据值直接使用Bean中的对应名称即可
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);
测试如下:
有时候会出现sql语句明明能查到数据,但在代码中就是获取不到值,这是因为数据库中表的字段名和我们代码中的属性名不一致,也是就是说:在mysql中会自行将我们代码属性中非首字母的大写字母(如:userName)转化成小写字母并加上下划线(转换后:user_name),也就是驼峰命名法;mybatis默认是不解析驼峰命名的;我们需要在yml配置文件或properties文件中加上一句配置,来开启驼峰命名:
mybatis.configuration.mapUnderscoreToCamelCase=true
自定义mybatis的配置规则
数据库使用驼峰命名法department_name,而配置类中用的是departmentName;则默认获取不到数据;需要给容器中添加一个ConfigurationCustomizer;:
@org.springframework.context.annotation.Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer() {
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
在当我们的Mapper接口非常多的时候,需要在每个类上添加@Mapper注解,这样会有点麻烦;我们可以在主启动类上添加一个扫描Mapper类的注解:
@MapperScan(value = "com.mybatis.mybatis.mapper")
@SpringBootApplication
public class MybatisApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisApplication.class, args);
}
}
这样程序在启动的时候会自动将路径com.mybatis.mybatis.mapper下的所有文件扫描并为Mapper接口。而不用每个类都加@Mapper注解
配置文件版Mybatis
配置版主要是在配置文件中指定Mybatis的配置文件路径
mybatis:
config-location: classpath:mybatis/mybatis-config.xml 指定全局配置文件的位置
mapper-locations: classpath:mybatis/mapper/*.xml 指定sql映射文件的位置
更多学习可参照
http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
SpringBoot整合JPA操作数据库
JPA是基于ORM(Object Relational Mapping)思想的;
- 编写一个实体类(bean)和数据表进行映射,并配置好映射关系;
/**
* @author :will
* @date :2019/8/11 20:58
* @description:使用JPA注解配置映射关系
*/
@Entity //告诉JPA这是一个实体类
@Table(name = "users") //用@Table来指定和哪个表对应; 如果省略,则默认表明就是类名users
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })
public class users {
@Id//标注这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
private int uid;
@Column(name = "username",length = 20)//这是和数据表对应的列名
private String username;
@Column(name = "password")//如果省略则默认列名就是属性名
private String password;
@Column
private String gender;
@Column
private String role;
//get和set方法省略
}
- 编写一个Dao接口,来操作对应的数据表(Repository)基本的操作方法已经在JpaRepository类中写好,直接调用就行
//继承JPARepository来完成对数据库的操作
public interface UserRepository extends JpaRepository<users,Integer> {
}
- 基本配置JpaRepository
spring:
jpa:
hibernate:
# 更新或者创建数据表结构,在每次启动项目的时候会自动进行检查更新或创建
ddl-auto: update
# 控制台显示SQL
show-sql: true
- 编写控制类,在控制类中直接注入自己编写的UserRepository接口,而后直接调用该接口中的方法进行操作数据库:
@RestController
public class UserController {
@Autowired
UserRepository userRepository; @GetMapping("/jpa/{id}")
public users getUser(@PathVariable("id") Integer id){
users us=userRepository.getOne(id);
return us;
}
@GetMapping("/jpa")
public users insertUsers(users us){
users save= userRepository.save(us);
return save;
}
}
JPA中对象一对一、一对多操作
一对多操作
- 在一对多操作中一的一方需要添加一个Set类型的属性,存放多的一方,并且数据库中表不需要更改,因为前边配置了ddl-auto: update ,这会让数据库自行根据需要添加列:
public class users {
@Id//标注这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
private int uid;
@Column(name = "username",length = 20)//这是和数据表对应的列名
private String username;
@Column(name = "password")//如果省略则默认列名就是属性名
private String password;
@Column
private String gender;
@Column
private String role;
@OneToMany(targetEntity = Employee.class,cascade = {CascadeType.PERSIST}) //cascade级联新增
@JoinColumn(name = "use_emp_id",referencedColumnName = "uid")
private Set<Employee> employees=new HashSet<Employee>(0);
//TODO Get()
//TODO Set()
//TODO ToString()
}
- 在多的一方不需要添加任何信息;
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "lastName",length = 20)
private String lastName;
@Column(name = "email")
private String email;
@Column(name = "gender")
private int gender;
@Column(name = "d_id")
private int d_id;
//TODO Get();
//TODO Set();
//TODO ToString()
}
这里两个类都省略了get和set以及ToString方法,请自行添加;
- 测试代码:
测试使用项目Junit测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdatajpaApplicationTests {
/*OneToMany测试*/
@Autowired
UserRepository userRepository;
//这两个接口生成方法一致,都是只继承JpaRepository即可,无需任何多于代码;唯一区别就是一个修改一下类即可,如下
//JpaRepository<users,Integer>
//JpaRepository<Employee,Integer>
@Autowired
EmployeeRepository employeeRepository;
@Test
@Transactional @Rollback(false)
public void contextLoads() {
users us=new users();
us.setUsername("OneToMany");
us.setPassword("123456");
Employee employee=new Employee();
employee.setLastName("many");
employee.setGender(2);
Employee employee1=new Employee();
employee1.setLastName("many1");
employee1.setGender(1);
HashSet<Employee> emplist=new HashSet<Employee>();
emplist.add(employee);
emplist.add(employee1);
us.setEmployees(emplist);
userRepository.save(us);
users us1=userRepository.getOne(12);
System.out.println(us1);
}
}
一对一的只是把Set 换成Employee类型,@OneToMany换成@OneToOne;自行参悟去吧!