Spring Boot(3)-使用mysql


目录(?)[+]

  1. 1JPA
    1. Spring Data Jpa 极大简化了数据库访问层代码只要3步就能搞定一切
    2. 1 添加pomxml依赖
    3. 2 配置数据库连接
    4. 3 编写Entity类依照JPA规范定义实体
    5. 4 编写Repository接口依靠SpringData规范定义数据访问接口注意只要接口不需要任何实现     5 写一小陀配置文件 Spring Scheme配置方式极大地简化了配置方式
    6. 1Maven pomxml文件
    7. 2属性配置文件applicationproperties
    8. 3实体
    9. 4实体的数据访问层Dao

    10. 5业务逻辑层service
    11. 6测试的控制器CityController
    12. 接口放在srcmainjavacomcitydataweb包中具体代码如下
  2. 2JDBC
    1. JDBC 连接数据库

    2. 连接池说明

spring Boot构建的Web应用中,基于MySQL数据库的几种数据库连接方式进行介绍。 
   包括JDBC、JPA、MyBatis、多数据源和事务。

Spring Boot的Web应用中使用Mysq数据库,也充分展示Spring Boot的优势(尽可能少的代码和配置)。数据访问层我们将使用Spring Data JPA和hibernate(JPA的实现之一)。

  注意:如果你想JDBC和JPA可以一起使用,Spring Boot 是支持的,你只需要把JDBC和JPA的依赖都添加在pom.xml 中即可。无需其他特殊处理。

1、JPA

Spring Data Jpa 极大简化了数据库访问层代码,只要3步,就能搞定一切

1. 添加pom.xml依赖

2. 配置数据库连接

3. 编写Entity类,依照JPA规范,定义实体

4. 编写Repository接口,依靠SpringData规范,定义数据访问接口(注意,只要接口,不需要任何实现)
     5. 写一小陀配置文件 (Spring Scheme配置方式极大地简化了配置方式)

1.Maven pom.xml文件

要使用MySQL,需要引入对应的connector,因此,首先在pom文件中添加如下依赖:

<dependency>
   <groupId>mysqlgroupId>
   <artifactId>mysql-connector-javaartifactId>
dependency>

<dependencies>
  <dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
  dependency>
  <dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-jpaartifactId>
  dependency>
  <dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
  dependency>
dependencies>

2.属性配置文件application.properties

在src/main/resources/application.properties中设置数据源和jpa配置。

spring.datasource.url = jdbc:mysql://localhost:3306/test
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

# stripped before adding them to the entity manager)
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

全部的配置都在如上的文件中了,不需要另外的XML配置和Java配置。

上文中的数据库配置,你需要换成你的数据库的地址和用户名密码。

hibernate的ddl-auto=update配置表名,数据库的表和列会自动创建(根据Java实体的熟悉), 这里 可以看到更多得hibernate配置。

如果希望通过Hibernate依靠Entity类自动创建数据库和数据表,则还需要加上配置项—— spring.jpa.hibernate.ddl-auto=create-drop
PS:在生产环境中不要使用create-drop,这样会在程序启动时先删除旧的,再自动创建新的,最好使用update;还可以通过设置 spring.jpa.show-sql = true来显示自动创建表的SQL语句,通过 spring.jpa.database = MYSQL指定具体的数据,如果不明确指定Spring boot会根据classpath中的依赖项自动配置。

在Spring项目中,如果数据比较简单,我们可以考虑使用JdbcTemplate,而不是直接定义Datasource,配置jdbc的代码如下:

@Autowired
private JdbcTemplate jdbcTemplate;

只要定义了上面这个代码,Spring Boot会自动创建一个Datasource对象,然后再创建一个jdbctemplate对象来管理datasource,通过jdbctemplate操作数据库可以减少大量模板代码。如果你对SpringBoot的原理感兴趣,可以在org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration类中查看其具体实现。


3.实体

我们本例是一个城市相关系统:
数据库中应该具备以下领域对象(domain object)
    创建一个City实体。User实体和Mysql数据库的city表相对应。
首先在src\main\java\com\city\data\下建立包domain,然后再在这个包下建立相应的实体类

package com.city.data.domain;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Table(name = "city")
public class City implements Serializable {
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue
	private int cityId;
	
	@Column(nullable = false)
	private String name;
	@Column(nullable = false)
	private int provinceId;
	
	public City() {
	}
	public City( int cityId) {
		super();
		this.cityId = cityId;
	}
	public int  getCityId() {  
	      return cityId;  
	 }  
	public void setCityId(int id) {  
	     this.cityId = id;  
	}    
        ......
	
}

4.实体的数据访问层Dao

创建完实体类,还需要创建CityRepository接口,该接口继承自Repository,这个接口放在src\main\java\com\city\data\service包中,具体代码如下:
package com.city.data.service;
/**
 *DAO层
 */
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;

import com.city.data.domain.City;
interface CityRepository extends Repository {
	City findByName(String name);
}

  我们都没有写一行SQL语句,也没有在代码中涉及到数据库连接、建立查询等方面的内容。只有实体类上的各种注解表明我们在于数据库做交互:@Entity,@Repository,@Id,@GeneratedValue,@ManyToOne,@ManyToMany以及@OneToMany,这些注解属于JavaPersistance API。我们通过Respository接口的子接口与数据库交互,同时由Spring建立对象与数据库表、数据库表中的数据之间的映射关系。下面依次说明这些注解的含义和使用:

  • @Entity,说明被这个注解修饰的类应该与一张数据库表相对应,表的名称可以由类名推断,当然了,也可以明确配置,只要加上@Table(name = "books")即可。需要特别注意,每个Entity类都应该有一个protected访问级别的无参构造函数,用于给Hibernate提供初始化的入口。
  • @Id and @GeneratedValue:@Id注解修饰的属性应该作为表中的主键处理、@GeneratedValue修饰的属性应该由数据库自动生成,而不需要明确指定。
  • @ManyToOne, @ManyToMany表明具体的数据存放在其他表中,在这个例子里,书和作者是多对一的关系,书和出版社是多对一的关系,因此book表中的author和publisher相当于数据表中的外键;并且在Publisher中通过@OneToMany(mapped = "publisher")定义一个反向关联(1——>n),表明book类中的publisher属性与这里的books形成对应关系。
  • @Repository 用来表示访问数据库并操作数据的接口,同时它修饰的接口也可以被component scan机制探测到并注册为bean,这样就可以在其他模块中通过@Autowired织入。
      我们可以添加自定义的接口函数,JPA会提供对应的SQL查询,例如,在本例中的CityRepository中可以增加findByName(String name)函数,JPA会自动创建对应的SQL查询——根据name查询城市,这种将方法名转换为SQL语句的机制十分方便且功能强大,例如你可以增加类似findByNameIgnoringCase(String name)这种复杂查询。


5.业务逻辑层service

接口放在src\main\java\com\city\data\service包中,具体代码如下:

package com.city.data.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;


import com.city.data.domain.City;

@Component("cityService")
@Transactional
public class CityServiceImpl implements CityService {

	private final CityRepository cityRepository;
	@Autowired
	public CityServiceImpl(CityRepository cityRepository) {
		this.cityRepository = cityRepository;
	}


	//@Override
	public City getCity(String cityName) {
		Assert.notNull(cityName, "Name must not be null");
		return this.cityRepository.findByName(cityName);
	}
}

6.测试的控制器CityController

新建一个查询控制器CityController,

接口放在src\main\java\com\city\data\web包中,具体代码如下:

package com.city.data.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;


import com.city.data.service.CityService;
import com.city.data.domain.City;;


//原始格式
//@Controller
//json格式
@RestController
public class CityController {


	@Autowired
	private CityService cityService;


	@RequestMapping("/")
	@ResponseBody
	@Transactional(readOnly = true)
	public int getBeijing() {
		//return "helloWorld";
		return this.cityService.getCity("beijing").getCityId();
	}

	/**
	 * @PathVariable是用来获得请求url中的动态参数的
	 * @param name
	 * @return
	 */
	 @RequestMapping(value = "/{name}", method = RequestMethod.GET)
	public Map getCity( @PathVariable String name) {
	     City city =  this.cityService.getCity(name);

	    Map response = new LinkedHashMap<>();
	    response.put("msg", "get city with name(" + name +")");
	    response.put("city", city);
	    return response;
	 }

}

你可以使用浏览器访问url http://127.0.0.1:8080

2、JDBC

JDBC 连接数据库

1、属性配置文件(application.properties)

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driverClassName=com.mysql.jdbc.Driver

如果使用JNDI,则可以替代 spring.datasource 的 url、username、password,如:

spring.datasource.jndi-name=java:tomcat/datasources/example 


值得一提的是,无论是Spring Boot默认的DataSource配置还是你自己的DataSource bean,都会引用到外部属性文件中的属性配置。所以假设你自定义的DataSource bean,你可以在定义bean时设置属性,也可以在属性文件中,以“spring.datasource.*”的方式使属性配置外部化。

2、pom.xml 配置maven依赖

        
        
            mysql
            mysql-connector-java
         
         
         
            org.springframework.boot
            spring-boot-starter-jdbc
          


3、Java代码范例

CityServiceImpl.java

注意,使用jdbc要有变量

@Autowired
private JdbcTemplate jdbcTemplate;


[java] view plain copy
print ?
  1. "code" class="java">/* 
  2.  */  
  3.   
  4. package com.city.data.service;  
  5.   
  6.   
  7. import org.springframework.beans.factory.annotation.Autowired;  
  8. import org.springframework.data.domain.Page;  
  9. import org.springframework.data.domain.Pageable;  
  10. import org.springframework.stereotype.Component;  
  11. import org.springframework.transaction.annotation.Transactional;  
  12. import org.springframework.util.Assert;  
  13. import org.springframework.util.StringUtils;  
  14. import org.springframework.jdbc.core.JdbcTemplate;  
  15. import org.springframework.jdbc.core.RowMapper;  
  16.   
  17.   
  18.   
  19.   
  20.   
  21. import java.sql.ResultSet;  
  22. import java.sql.SQLException;  
  23. import java.util.*;  
  24.   
  25. import com.city.data.domain.City;  
  26. import com.city.data.common.JdbcSQL;  
  27.   
  28. @Component("cityService")  
  29. @Transactional  
  30.   
  31. public class CityServiceImpl implements CityService {  
  32.   
  33.     private final CityRepository cityRepository;  
  34.   
  35.     @Autowired  
  36.     private JdbcTemplate jdbcTemplate;  
  37.       
  38.     @Autowired  
  39.     public CityServiceImpl(CityRepository cityRepository) {  
  40.         this.cityRepository = cityRepository;  
  41.   
  42.     }  
  43.       
  44.     /** 
  45.      *  
  46.      */  
  47.      public List getCityList(CitySearchCriteria criteria){  
  48.             String sql = "SELECT *  FROM city";  
  49.             String cityName = criteria.getName();  
  50.             int  provinceid  = criteria.getProvinceId();  
  51.             String where  = "";  
  52.             if(provinceid > 0 ) {  
  53.                 where += " province_id=" + provinceid;  
  54.             }  
  55.             if(StringUtils.hasLength(cityName) ) {  
  56.                 where += " name=" + cityName;  
  57.             }  
  58.             if(!where.isEmpty() ) {  
  59.                 sql =sql + " where "  + where;  
  60.             }  
  61.               
  62.               
  63.             return (List) jdbcTemplate.query(sql, new RowMapper(){  
  64.                 @Override  
  65.                 public City mapRow(ResultSet rs, int rowNum) throws SQLException {  
  66.                     City  city = new City();  
  67.                     city.setCityId(rs.getInt("city_id"));  
  68.                     city.setName(rs.getString("name"));  
  69.                     city.setMap(rs.getString("map"));  
  70.                     city.setProvinceId(rs.getInt("province_id"));  
  71.                     return city;  
  72.                 }  
  73.   
  74.             });  
  75.         }  
  76.   
  77.   
  78.       
  79.     public  List getCityList2(Map condition){  
  80.         JdbcSQL jdbcSQL  =new JdbcSQL();  
  81.         jdbcSQL.setTable("city");  
  82.         jdbcSQL.setConditon(condition);  
  83.         return jdbcSQL.selectByCondition();  
  84.     }  
  85.   
  86.     public  List> getCityList2(Map condition) {  
  87.             String sql = "select * from city";  
  88.             return jdbcTemplate.queryForList(sql);  
  89.               
  90.     }  
  91.   
  92. }  
/*
 */

package com.city.data.service;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;





import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

import com.city.data.domain.City;
import com.city.data.common.JdbcSQL;

@Component("cityService")
@Transactional

public class CityServiceImpl implements CityService {

	private final CityRepository cityRepository;

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	@Autowired
	public CityServiceImpl(CityRepository cityRepository) {
		this.cityRepository = cityRepository;

	}
	
	/**
	 * 
	 */
	 public List getCityList(CitySearchCriteria criteria){
	        String sql = "SELECT *  FROM city";
	        String cityName = criteria.getName();
	        int  provinceid  = criteria.getProvinceId();
	        String where  = "";
	        if(provinceid > 0 ) {
	        	where += " province_id=" + provinceid;
	        }
	        if(StringUtils.hasLength(cityName) ) {
	        	where += " name=" + cityName;
	        }
	        if(!where.isEmpty() ) {
	        	sql =sql + " where "  + where;
	        }
	        
	        
	        return (List) jdbcTemplate.query(sql, new RowMapper(){
	            @Override
	            public City mapRow(ResultSet rs, int rowNum) throws SQLException {
	                City  city = new City();
	                city.setCityId(rs.getInt("city_id"));
	                city.setName(rs.getString("name"));
	                city.setMap(rs.getString("map"));
	                city.setProvinceId(rs.getInt("province_id"));
	                return city;
	            }

	        });
	    }


	
	public  List getCityList2(Map condition){
		JdbcSQL jdbcSQL  =new JdbcSQL();
		jdbcSQL.setTable("city");
		jdbcSQL.setConditon(condition);
		return jdbcSQL.selectByCondition();
	}

	public  List> getCityList2(Map condition) {
		 	String sql = "select * from city";
	        return jdbcTemplate.queryForList(sql);
	        
	}

}

 
   

然后启动项目,访问地址: http://localhost:8080/

连接池说明

Tomcat7之前,Tomcat本质应用了DBCP连接池技术来实现的JDBC数据源,但在Tomcat7之后,Tomcat提供了新的JDBC连接池方案,作为DBCP的替换或备选方案,解决了许多之前使用DBCP的不利之处,并提高了性能。详细请参考:http://wiki.jikexueyuan.com/project/tomcat/tomcat-jdbc-pool.html

Spring Boot为我们准备了最佳的数据库连接池方案,只需要在属性文件(例如application.properties)中配置需要的连接池参数即可。 
我们使用Tomcat数据源连接池,需要依赖tomcat-jdbc,只要应用中添加了spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa依赖,则无需担心这点,因为将会自动添加 tomcat-jdbc 依赖。 
假如我们想用其他方式的连接池技术,只要配置自己的DataSource bean,即可覆盖Spring Boot的自动配置。

请看我的数据源配置:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
spring.datasource.validation-query=SELECT 1
spring.datasource.test-on-borrow=false
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=18800
spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=0)

配置过连接池的开发人员对这些属性的意义都有所认识。

我们打开DEBUG日志输出,logback.xml 中添加:

<logger name="org.springframework.boot" level="DEBUG"/>
  • 1

然后启动项目,注意观察日志输出,如下图中会显示自动启用了连接池: 
 
我在上面的数据源配置中添加了过滤器,并设置了延迟时间为0(故意设置很低,实际项目中请修改):

spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=0)
  • 1

这个时候,我们访问 http://localhost:8080/myspringboot/stu/list 观察日志,会发现框架自动将大于该时间的数据查询进行警告输出,如下:


问题:

1、连接池的连接在最大生存时间 时间内没有请求数据库,再次使用的连接就报错。                      

     spring.datasource.max-lifetime=86400000 (单位 毫秒)

 2、如果连接池的连接长时间不使用(可能时间短于max-lifetime),但是超过mysql的wait_timeout的时间,mysql也会进行回收这个连接的。

my.cnf

wait_timeout=31536000

interactive_timeout=31536000

Mysql服务器默认的“wait_timeout”是8小时【也就是默认的值默认是28800秒】,也就是说一个connection空闲超过8个小时,Mysql将自动断开该connection,通俗的讲就是一个连接在8小时内没有活动,就会自动断开该连接。 wait timeout的值可以设定,但最多只能是2147483,不能再大了。也就是约24.85天 .

你可能感兴趣的:(springboot,mysql,spring,boot)