您的位置:首页 > 编程语言 > Java开发

二、spring Boot构建的Web应用中,基于MySQL数据库的几种数据库连接方式进行介绍

2017-08-11 14:46 1136 查看

包括JDBC、JPA、MyBatis、多数据源和事务。

一、JDBC连接数据库

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

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

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

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


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

2、pom.xml配置maven依赖

<!--MYSQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--SpringBootJDBC-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

3、Java代码范例

StudentService.java

packageorg.springboot.sample.service;

importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.util.List;

importorg.springboot.sample.entity.Student;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.jdbc.core.JdbcTemplate;
importorg.springframework.jdbc.core.RowMapper;
importorg.springframework.stereotype.Service;

@Service
publicclassStudentService{

@Autowired
privateJdbcTemplatejdbcTemplate;

publicList<Student>getList(){
Stringsql="SELECTID,NAME,SCORE_SUM,SCORE_AVG,AGEFROMSTUDENT";
return(List<Student>)jdbcTemplate.query(sql,newRowMapper<Student>(){

@Override
publicStudentmapRow(ResultSetrs,introwNum)throwsSQLException{
Studentstu=newStudent();
stu.setId(rs.getInt("ID"));
stu.setAge(rs.getInt("AGE"));
stu.setName(rs.getString("NAME"));
stu.setSumScore(rs.getString("SCORE_SUM"));
stu.setAvgScore(rs.getString("SCORE_AVG"));
returnstu;
}

});
}
}

Student.java实体类

packageorg.springboot.sample.entity;

importjava.io.Serializable;

publicclassStudentimplementsSerializable{

privatestaticfinallongserialVersionUID=2120869894112984147L;

privateintid;
privateStringname;
privateStringsumScore;
privateStringavgScore;
privateintage;

//节省文章长度,getset方法省略
}

StudentController.java

packageorg.springboot.sample.controller;

importjava.util.List;

importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springboot.sample.entity.Student;
importorg.springboot.sample.service.StudentService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/stu")
publicclassStudentController{

privatestaticfinalLoggerlogger=LoggerFactory.getLogger(StudentController.class);

@Autowired
privateStudentServicestudentService;

@RequestMapping("/list")
publicList<Student>getStus(){
logger.info("从数据库读取Student集合");
returnstudentService.getList();
}
}

本文对工程添加文件后工程结构图:



然后启动项目,访问地址:http://localhost:8080/myspringboot/stu/list响应结果如下:

[
{
id:1,
name:"小明",
sumScore:"252",
avgScore:"84",
age:1
},
{
id:2,
name:"小王",
sumScore:"187",
avgScore:"62.3",
age:1
},
{
id:3,
name:"莉莉",
sumScore:"",
avgScore:"",
age:0
},
{
id:4,
name:"柱子",
sumScore:"230",
avgScore:"76.7",
age:1
},
{
id:5,
name:"大毛",
sumScore:"",
avgScore:"",
age:0
},
{
id:6,
name:"亮子",
sumScore:"0",
avgScore:"0",
age:1
}

连接池说明

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

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

请看我的数据源配置:

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=SELECT1
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中添加:

<loggername="org.springframework.boot"level="DEBUG"/>

然后启动项目,注意观察日志输出,如下图中会显示自动启用了连接池:



在上面的数据源配置中添加了过滤器,并设置了延迟时间为0(故意设置很低,实际项目中请修改):

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

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

o.a.t.j.p.interceptor.SlowQueryReport:SlowQueryReportSQL=SELECTID,NAME,SCORE_SUM,SCORE_AVG,AGEFROMSTUDENT;time=3ms;

二、将介绍如何在springBoot工程中添加JPA作为持久化方式

修改pom.xml依赖

与上一篇介绍的jdbc不同的是spring-boot-starter-jdbc修改为spring-boot-starter-data-jpa即可,当然数据库驱动包也是不可少的,如下:

<!--MYSQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--SpringBootJPA-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>


注意:如果你想JDBC和JPA可以一起使用,SpringBoot是支持的,你只需要把JDBC和JPA的依赖都添加在pom.xml中即可。无需其他特殊处理,有关JDBC的使用介绍请看上一篇“Spring-BootJDBC连接数据库”。

修改属性配置文件

在属性配置文件中添加JPA相关属性,注意这些并非必须,我们如果只添加dataSource的url\username\password\driver-class-name也可以正常使用,有关JPA的其他配置都是可选的。

spring.jpa.database=
spring.jpa.show-sql=
spring.jpa.properties=
spring.jpa.generate-ddl=
spring.jpa.open-in-view=
spring.jpa.database-platform=
spring.jpa.hibernate.ddl-auto=
spring.data.jpa.repositories.enabled=
spring.jpa.hibernate.naming-strategy=

熟悉JPA的根据名字应基本知道这些分别的作用了。

传统上,JPA实体类在persistence.xml文件中指定的。使用SpringBoot,这个文件是没有必要的,因为它使用“实体扫描”,默认情况下主配置@EnableAutoConfiguration或@SpringBootApplication下面的所有包都将会被扫描。任何使用注解@Entity,@Embeddable或@MappedSuperclass的类都将被管理。

Java代码实例

一个接口

一个Controller

我们创建一个接口IScoreDao.Java,然后我们继承框架为我们提供好的接口Repository或CrudRepository(CrudRepository继承自Repository),其中为我们提供了对数据库的基本操作方法。

packageorg.springboot.sample.dao;

importjava.util.List;

importjavax.transaction.Transactional;

importorg.springboot.sample.entity.Score;
importorg.springframework.data.jpa.repository.Modifying;
importorg.springframework.data.jpa.repository.Query;
importorg.springframework.data.repository.CrudRepository;
importorg.springframework.data.repository.query.Param;

publicinterfaceIScoreDaoextendsCrudRepository<Score,Integer>{

@Transactional
@Modifying
@Query("updateScoretsett.score=:scorewheret.id=:id")
intupdateScoreById(@Param("score")floatscore,@Param("id")intid);

@Query("selecttfromScoret")
List<Score>getList();

}

注意,如果你其中使用了修改、新增、删除操作,则必须要在接口上面或者对应的方法上面添加@Transactional注解,否则会抛出异常。

实体类Score.java

packageorg.springboot.sample.entity;

importjava.io.Serializable;
importjava.util.Date;

importjavax.persistence.Column;
importjavax.persistence.Entity;
importjavax.persistence.GeneratedValue;
importjavax.persistence.Id;
importjavax.persistence.Table;

/**
*成绩
*
*/
@Entity
@Table(name="score")
publicclassScoreimplementsSerializable{

privatestaticfinallongserialVersionUID=8127035730921338189L;

@Id
@GeneratedValue
privateintid;

@Column(nullable=false,name="STUDENTID")//这里说一下,我使用指定数据库列的时候,使用小写会不起作用,修改为大写便正常了。不知道为何,如果遇到一样问题的可以尝试下。
privateintstuId;

@Column(nullable=false,name="SUBJECTNAME")
privateStringsubjectName;

@Column(nullable=false)
privatefloatscore;

@Column(nullable=false,name="EXAMTIME")
privateDateexamTime;

//省去get、set方法(占用文章空间)

}

ScoreController.java

packageorg.springboot.sample.controller;

importjava.util.List;

importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springboot.sample.dao.IScoreDao;
importorg.springboot.sample.entity.Score;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/score")
publicclassScoreController{

privatestaticfinalLoggerlogger=LoggerFactory.getLogger(ScoreController.class);

@Autowired
privateIScoreDaoscoreService;

@RequestMapping("/scoreList")
publicList<Score>getScoreList(){
logger.info("从数据库读取Score集合");
//测试更新数据库
logger.info("更新的行数:"+scoreService.updateScoreById(88.8f,2));
scoreService.delete(23);

returnscoreService.getList();
}
}

然后在浏览器访问地址:http://localhost:8080/myspringboot/score/scoreList测试。

最后要说明的是,Spring会自动为我们继承CrudRepository接口的接口创建实现类。我们只需要在使用的时候直接使用注解@Autowired注入即可(IScoreDao接口上也没有必要增加@Component、@Repository等注解)。
还有,我这里为了简单起见,直接将操作数据库的在Controller中使用,实际项目中,是不建议这样做的,IScoreDao的所属角色是数据库持久,我们还应当有Service(如ScoreService)来调用IScoreDao的方法,然后在Controller中调用Service中的方法。原因是因为,我们数据库访问层,都是接口定义方法,上面注解注入SQL和参数,没有具体的代码逻辑处理。如果我们想在执行SQL之前或之后执行逻辑处理,只能在Service中或者Controller(不建议)中。
我们严格按照这种方式去做(持久层只与SQL有关,通过接口定义无逻辑处理),这样才是彻彻底底的持久层。越严格的规范制度,在某种程度上来说其实越有利于代码的管理和项目代码的迭代发展。

当然,如果你实在想要实现自己的class实现类,下面会附上一个实例代码,在此之前,我们先看一个图片:



这个图是Spring使用动态代理创建的接口实例,可以看出,其使用的是SimpleJpaRepository类,所以如果我们实现自己的Repository,可以扩展SimpleJpaRepository并实现自己的factory-class入手,这里不做详解。注意凡事实现Repository接口的实现类都不需要添加@Repository注解,否则你会遇到问题。

本文介绍JPA相比上一篇关于JDBC的介绍增加的文件工程截图为:



熟悉其中一种持久数据的方法后,其他类似的都大同小异。

三、SpringBoot种配置MyBatis

其实mybatis官网在2015年11月底就已经发布了对SpringBoot集成的Release版本,Github上有代码:https://github.com/mybatis/mybatis-spring-boot
前面对JPA和JDBC连接数据库做了说明,本文也是参考官方的代码做个总结。

先说个题外话,SpringBoot默认使用org.apache.tomcat.jdbc.pool.DataSource
现在有个叫HikariCP的JDBC连接池组件,据说其性能比常用的c3p0、tomcat、bone、vibur这些要高很多。
我打算把工程中的DataSource变更为HirakiDataSource,做法很简单:
首先在application.properties配置文件中指定dataSourceType

spring.datasource.type=com.zaxxer.hikari.HikariDataSource

然后在pom中添加Hikari的依赖

<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<!--版本号可以不用指定,SpringBoot会选用合适的版本-->
</dependency>

言归正传,下面说在springBoot中配置MyBatis。
关于在SpringBoot中集成MyBatis,可以选用基于注解的方式,也可以选择xml文件配置的方式。通过对两者进行实际的使用,还是建议使用XML的方式(官方也建议使用XML)。

下面将介绍通过xml的方式来实现查询,其次会简单说一下注解方式,最后会附上分页插件(PageHelper)的集成。

一、通过xml配置文件方式

1、添加pom依赖

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<!--请不要使用1.0.0版本,因为还不支持拦截器插件,1.0.1-SNAPSHOT是博主写帖子时候的版本,大家使用最新版本即可-->
<version>1.0.1-SNAPSHOT</version>
</dependency>

2、创建接口Mapper(不是类)和对应的Mapper.xml文件

定义相关方法,注意方法名称要和Mapper.xml文件中的id一致,这样会自动对应上
StudentMapper.Java

packageorg.springboot.sample.mapper;

importjava.util.List;

importorg.springboot.sample.entity.Student;

/**
*StudentMapper,映射SQL语句的接口,无逻辑实现
*
*/
publicinterfaceStudentMapperextendsMyMapper<Student>{

List<Student>likeName(Stringname);

StudentgetById(intid);

StringgetNameById(intid);

}

MyMapper.java

packageorg.springboot.sample.config.mybatis;

importtk.mybatis.mapper.common.Mapper;
importtk.mybatis.mapper.common.MySqlMapper;

/**
*被继承的Mapper,一般业务Mapper继承它
*
*/
publicinterfaceMyMapper<T>extendsMapper<T>,MySqlMapper<T>{
//TODO
//FIXME特别注意,该接口不能被扫描到,否则会出错
}

StudentMapper.xml

<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="org.springboot.sample.mapper.StudentMapper">

<!--type为实体类Student,包名已经配置,可以直接写类名-->
<resultMapid="stuMap"type="Student">
<idproperty="id"column="id"/>
<resultproperty="name"column="name"/>
<resultproperty="sumScore"column="score_sum"/>
<resultproperty="avgScore"column="score_avg"/>
<resultproperty="age"column="age"/>
</resultMap>

<selectid="getById"resultMap="stuMap"resultType="Student">
SELECT*
FROMSTUDENT
WHEREID=#{id}
</select>

<selectid="likeName"resultMap="stuMap"parameterType="string"resultType="list">
SELECT*
FROMSTUDENT
WHERENAMELIKECONCAT('%',#{name},'%')
</select>

<selectid="getNameById"resultType="string">
SELECTNAME
FROMSTUDENT
WHEREID=#{id}
</select>

</mapper>

3、实体类

packageorg.springboot.sample.entity;

importjava.io.Serializable;

/**
*学生实体
*
*/
publicclassStudentimplementsSerializable{

privatestaticfinallongserialVersionUID=2120869894112984147L;

privateintid;
privateStringname;
privateStringsumScore;
privateStringavgScore;
privateintage;

//getset方法省略

}

4、修改application.properties配置文件

mybatis.mapper-locations=classpath*:org/springboot/sample/mapper/sql/mysql/*Mapper.xml
mybatis.type-aliases-package=org.springboot.sample.entity

5、在Controller或Service调用方法测试

@Autowired
privateStudentMapperstuMapper;

@RequestMapping("/likeName")
publicList<Student>likeName(@RequestParamStringname){
returnstuMapper.likeName(name);
}

二、使用注解方式

查看官方Git上的代码使用注解方式,配置上很简单,使用上要对注解多做了解。至于xml和注解这两种哪种方法好,众口难调还是要看每个人吧。

1、启动类(我的)中添加@MapperScan注解

@SpringBootApplication
@MapperScan("sample.mybatis.mapper")
publicclassSampleMybatisApplicationimplementsCommandLineRunner{

@Autowired
privateCityMappercityMapper;

publicstaticvoidmain(String[]args){
SpringApplication.run(SampleMybatisApplication.class,args);
}

@Override
publicvoidrun(String...args)throwsException{
System.out.println(this.cityMapper.findByState("CA"));
}

}

2、在接口上使用注解定义CRUD语句

packagesample.mybatis.mapper;

importorg.apache.ibatis.annotations.Param;
importorg.apache.ibatis.annotations.Select;

importsample.mybatis.domain.City;

/**
*@authorEddúMeléndez
*/
publicinterfaceCityMapper{

@Select("SELECT*FROMCITYWHEREstate=#{state}")
CityfindByState(@Param("state")Stringstate);

}

其中City就是一个普通Java类。
关于MyBatis的注解,有篇文章讲的很清楚,可以参考:http://blog.csdn.net/luanlouis/article/details/35780175

三、集成分页插件

这里与其说集成分页插件,不如说是介绍如何集成一个plugin。MyBatis提供了拦截器接口,我们可以实现自己的拦截器,将其作为一个plugin装入到SqlSessionFactory中。
Github上有位开发者写了一个分页插件,我觉得使用起来还可以,挺方便的。
Github项目地址:https://github.com/pagehelper/Mybatis-PageHelper

下面简单介绍下:
首先要说的是,Spring在依赖注入bean的时候,会把所有实现MyBatis中Interceptor接口的所有类都注入到SqlSessionFactory中,作为plugin存在。既然如此,我们集成一个plugin便很简单了,只需要使用@Bean创建PageHelper对象即可。

1、添加pom依赖

<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.0</version>
</dependency>

2、新增MyBatisConfiguration.java

packageorg.springboot.sample.config;

importjava.util.Properties;

importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;

importcom.github.pagehelper.PageHelper;

/**
*MyBatis配置
*
*/
@Configuration
publicclassMyBatisConfiguration{

privatestaticfinalLoggerlogger=LoggerFactory.getLogger(MyBatisConfiguration.class);

@Bean
publicPageHelperpageHelper(){
logger.info("注册MyBatis分页插件PageHelper");
PageHelperpageHelper=newPageHelper();
Propertiesp=newProperties();
p.setProperty("offsetAsPageNum","true");
p.setProperty("rowBoundsWithCount","true");
p.setProperty("reasonable","true");
pageHelper.setProperties(p);
returnpageHelper;
}

}

3、分页查询测试

@RequestMapping("/likeName")
publicList<Student>likeName(@RequestParamStringname){
PageHelper.startPage(1,1);
returnstuMapper.likeName(name);
}

更多参数使用方法,详见PageHelper说明文档(上面的Github地址)。


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: