动力节点王鹤springboot3第四章访问数据库_第1页
动力节点王鹤springboot3第四章访问数据库_第2页
动力节点王鹤springboot3第四章访问数据库_第3页
动力节点王鹤springboot3第四章访问数据库_第4页
动力节点王鹤springboot3第四章访问数据库_第5页
已阅读5页,还剩29页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

springboot3第四章4访问数据库SpringBoot框架为SQL数据库提供了广泛的支持,既有用JdbcTemplate直接访问JDBC,同时支持“objectrelationalmapping”技术(如Hibernate,MyBatis)。SpringData独立的项目提供对多种关系型和非关系型数据库的访问支持。比如MySQL,Oracle,MongoDB,Redis,R2DBC,ApacheSolr,Elasticsearch...SpringBoot也支持嵌入式数据库比如H2,HSQL,andDerby。这些数据库只需要提供jar包就能在内存中维护数据。我们这章访问关系型数据库。4.1DataSource通常项目中使用MySQL,Oracle,PostgreSQL等大型关系数据库。Java中的jdbc技术支持了多种关系型数据库的访问。在代码中访问数据库,我们需要知道数据库程序所在的ip,端口,访问数据库的用户名和密码以及数据库的类型信息。以上信息用来初始化数据源,数据源也就是DataSource。数据源表示数据的来源,从某个ip上的数据库能够获取数据。javax.sql.DataSource接口表示数据源,提供了标准的方法获取与数据库绑定的连接对象(Connection)。javax.sql.Connection是连接对象,在Connection上能够从程序代码发送查询命令,更新数据的语句给数据库;同时从Connection获取命令的执行结果。Connection很重要,像一个电话线把应用程序和数据库连接起来。DataSource在application配置文件中以spring.datasource.*作为配置项。类似下面的代码:spring.datasource.url=jdbc:mysql://localhost/mydbspring.datasource.username=dbuserspring.datasource.password=dbpassDataSourceProperties.java是数据源的配置类,更多配置参考这个类的属性。SpringBoot能够从spring.datasource.url推断所使用的数据驱动类,如果需要特殊指定请设置spring.datasource.driver-class-name为驱动类的全限定名称。SpringBoot支持多种数据库连接池,优先使用HikariCP,其次是Tomcatpooling,再次是CommonsDBCP2,如果以上都没有,最后会使用OracleUCP连接池。当项目中starter依赖了spring-boot-starter-jdbc或者spring-boot-starter-data-jpa默认添加HikariCP连接池依赖,也就是默认使用HikariCP连接池。4.2轻量的JdbcTemplate使用JdbcTemplate我们提供自定义SQL,Spring执行这些SQL得到记录结果集。JdbcTemplate和NamedParameterJdbcTemplate类是自动配置的,您可以@Autowire注入到自己的Bean中。开箱即用。JdbcTemplate执行完整的SQL语句,我们将SQL语句拼接好,交给JdbcTemplate执行,JdbcTemplate底层就是使用JDBC执行SQL语句。是JDBC的封装类而已。NamedParameterJdbcTemplate可以在SQL语句部分使用“:命名参数”作为占位符,对参数命名,可读性更好。NamedParameterJdbcTemplate包装了JdbcTemplate对象,“:命名参数”解析后,交给JdbcTemplate执行SQL语句。JdbcTemplateAutoConfiguration自动配置了JdbcTemplate对象,交给JdbcTemplateConfiguration创建了JdbcTemplate对象。并对JdbcTemplate做了简单的初始设置(QueryTimeout,maxRows等)。4.2.1准备环境访问数据库先准备数据库的script。SpringBoot能够自动执行DDL,DML脚本。两个脚本文件名称默认是schema.sql和data.sql。脚本文件在类路径中自动加载。自动执行脚本还涉及到spring.sql.init.mode配置项:always:总是执行数据库初始化脚本never:禁用数据库初始化更进一步SpringBoot处理特定的数据库类型,为特定的数据库定制script文件。首先设置spring.sql.init.platform=hsqldb、h2、oracle、mysql、postgresql等等,其次准备schema-${platform}.sql、data-${platform}.sql脚本文件。准备数据库和表脚本首先创建数据库,安装MySQL8.5。有可用的MySQL数据库就可以,最好是5以上版本。数据库名称Blog,表目前使用一个article(文章表),初始两条数据。schema.sqlCREATE

TABLE

`article`

(

`id`

int(11)

NOT

NULL

AUTO_INCREMENT

COMMENT

'主键',

`user_id`

int(11)

NOT

NULL

COMMENT

'作者ID',

`title`

varchar(100)

NOT

NULL

COMMENT

'文章标题',

`summary`

varchar(200)

DEFAULT

NULL

COMMENT

'文章概要',

`read_count`

int(11)

unsigned

zerofill

NOT

NULL

COMMENT

'阅读读数',

`create_time`

datetime

NOT

NULL

COMMENT

'创建时间',

`update_time`

datetime

NOT

NULL

COMMENT

'最后修改时间',

PRIMARY

KEY

(`id`))

ENGINE=InnoDB

AUTO_INCREMENT=1

DEFAULT

CHARSET=utf8mb4;data.sqlINSERT

INTO

`article`

VALUES

('1','2101','SpringBoot核心注解','核心注解的主要作用','00000008976','2023-01-16

12:11:12','2023-01-16

12:11:19');INSERT

INTO

`article`

VALUES

('2','356752','JVM调优','HotSpot虚拟机详解','00000000026','2023-01-16

12:15:27','2023-01-16

12:15:30');创建SpringBoot工程新建SpringBoot工程Lession09-JdbcTemplate构建工具:Maven包名:com.bjpowernode.jdbcJDK:19Starter依赖:Lombok,MySQLDriver,JDBCAPIMaven依赖(pom.xml)<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency>

<groupId>com.mysql</groupId>

<artifactId>mysql-connector-j</artifactId>

<scope>runtime</scope></dependency><dependency>

<groupId>jectlombok</groupId>

<artifactId>lombok</artifactId>

<optional>true</optional></dependency><dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope></dependency>IDEAMavenTool查看依赖列表依赖包含了连接池com.zaxxer:HikariCP:5.0.1,spring-jdbc6.0.3,mysql驱动mysql-connector-j8.0.31。4.2.2JdbcTemplate访问MySQL项目中依赖了spring-jdbc6.0.3,JdbcTemplate对象会自动创建好。把JdbcTemplate对象注入给你的Bean,再调用JdbcTemplate的方法执行查询,更新,删除的SQL。JdbcTemplate上手快,功能非常强大。提供了丰富、实用的方法,归纳起来主要有以下几种类型的方法:(1)execute方法:可以用于执行任何SQL语句,常用来执行DDL语句。(2)update、batchUpdate方法:用于执行新增、修改与删除等语句。(3)query和queryForXXX方法:用于执行查询相关的语句。(4)call方法:用于执行数据库存储过程和函数相关的语句。我们在已经创建了SpringBoot工程,在工程上继续添加代码,完成对Blog库,article表的CRUD。step1:将schema.sql,data.sql拷贝到resources目录step2:修改pertiesspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=falsespring.datasource.username=rootspring.datasource.password=123456#总是执行数据库脚本,以后设置为neverspring.sql.init.mode=alwaysstep3:创建实体类ArticlePOLomok注解给类的属性生成set,get方法。默认和所有参数构造方法step4:单元测试,注入JdbcTemplate对象@SpringBootTestpublicclassTestJdbcTemplate{

@ResourceprivateJdbcTemplatejdbcTemplate;}测试聚合函数@TestvoidtestCount(){Stringsql="selectcount(*)asctfromarticle";Longcount=jdbcTemplate.queryForObject(sql,Long.class);System.out.println("文章总数="+count);

}测试“?”占位符@TestvoidtestQuery(){//?作为占位符Stringsql="select*fromarticlewhereid=?";//BeanPropertyRowMapper将查询结果集,列名与属性名称匹配,名称完全匹配或驼峰ArticlePOarticle=jdbcTemplate.queryForObject(sql,newBeanPropertyRowMapper<>(ArticlePO.class),1);System.out.println("查询到的文章="+article);

}测试自定义RowMapper测试List集合@TestvoidtestList(){Stringsql="select*fromarticleorderbyid";List<Map<String,Object>>listMap=jdbcTemplate.queryForList(sql);listMap.forEach(el->{el.forEach((field,value)->{

System.out.println("字段名称:"+field+",列值:"+value);

});System.out.println("===================================");

});}测试更新记录@TestvoidtestUpdate(){Stringsql="updatearticlesettitle=?whereid=?";//参数是从左往右第一个,第二个...intupdated=jdbcTemplate.update(sql,"Java核心技术思想",2);

System.out.println("更新记录:"+updated);

}4.2.3NamedParameterJdbcTemplateNamedParameterJdbcTemplate能够接受命名的参数,通过具名的参数提供代码的可读性,JdbcTemplate使用的是参数索引的方式。在使用模板的位置注入NamedParameterJdbcTemplate对象,编写SQL语句,在SQL中WHERE部分“:命名参数”。调用NamedParameterJdbcTemplate的诸如query,queryForObject,execute,update等时,将参数封装到Map中。step1:注入模板对象@ResourceprivateJdbcTemplatejdbcTemplate;step2:使用命名参数@TestvoidtestNameQuery(){//:参数名Stringsql="selectcount(*)asctfromarticlewhereuser_id=:uidandread_count>:num";

//key是命名参数Map<String,Object>param=newHashMap<>();param.put("uid",2101);param.put("num",0);

Longcount=nameJdbcTemplate.queryForObject(sql,param,Long.class);System.out.println("用户被阅读的文章数量="+count);}4.2.4多表查询多表查询关注是查询结果如何映射为JavaObject。常用两种方案:一种是将查询结果转为Map。列名是key,列值是value,这种方式比较通用,适合查询任何表。第二种是根据查询结果中包含的列,创建相对的实体类。属性和查询结果的列对应。将查询结果自定义RowMapper、ResultSetExtractor映射为实体类对象。现在创建新的表article_detail,存储文章内容,与article表是一对一关系。article_detail表CREATETABLE`article_detail`(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'注解',`article_id`int(11)NOTNULLCOMMENT'文章ID',`content`textNOTNULLCOMMENT'文章内容',PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=utf8mb4;需求:查询某个文章的全部属性,包括文章内容step1:创建新的实体类ArticleMainPO,将ArticlePO作为成员变量@Data@NoArgsConstructor@AllArgsConstructorpublicclassArticleMainPO{privateIntegerid;privateIntegeruserId;privateStringtitle;privateStringsummary;privateIntegerreadCount;privateLocalDateTimecreateTime;privateLocalDateTimeupdateTime;privateArticleDetailPOarticleDetail;}step2:查询一对一文章@TestvoidtestArticleContent(){Stringsql="""selectm.*,d.idasdetail_id,d.article_id,d.contentfromarticlemjoinarticle_detaildonm.id=d.article_idwherem.id=:id""";Map<String,Object>param=newHashMap<>();param.put("id",1);List<ArticleMainPO>list=nameJdbcTemplate.query(sql,param,(rs,rowNum)->{varid=rs.getInt("id");varuserId=rs.getInt("user_id");vartitle=rs.getString("title");varsummary=rs.getString("summary");varreadCount=rs.getInt("read_count");varcreateTime=newTimestamp(rs.getTimestamp("create_time").getTime()).toLocalDateTime();varupdateTime=newTimestamp(rs.getTimestamp("update_time").getTime()).toLocalDateTime();//文章详情vardetailId=rs.getInt("detail_id");varcontent=rs.getString("content");vararticleId=rs.getInt("article_id");ArticleDetailPOdetail=newArticleDetailPO();detail.setId(detailId);detail.setArticleId(articleId);detail.setContent(content);returnnewArticleMainPO(id,userId,title,summary,readCount,createTime,updateTime,detail);});list.forEach(m->{System.out.println("m.getId()="+m.getId());System.out.println("m.getArticleDetail()="+m.getArticleDetail());});}总结:JdbcTemplate的优点简单,灵活,上手快,访问多种数据库。对数据的处理控制能力比较强,RowMapper,ResultSetExtractor能够提供按需要灵活定制记录集与实体类的关系。缺点:对SQL要求高,适合对SQL比较了解,自定义查询结果比较多,调优需求的。JdbcTemplate对象的调整参数,比较少。可设置spring.jdbc.template.开头的配置项目,比如设置超时为10秒,spring.jdbc.template.query-timeout=10。4.3MyBatis数据库访问MyBatis,MyBatis-Plus国内很常用,掌握了MyBatis,MyBatis-Plus就会了大部分了。MyBatis-Plus附加的功能需要单独学习。我们以MyBatis来自介绍SpringBoot集成ORM框架。MyBatis使用最多的是mapperxml文件编写SQL语句。本章使用MyBatis的注解,JDK新特性文本块,以及Record完成java对象和表数据的处理。4.3.1单表CRUD首先向blog数据库的article表添加新的文章,以及修改,查询文章。在新工程Lession10-MyBatis集成MyBatis框架。项目包名com.bjpowernode.orm。依赖需要mysql驱动、mybatis依赖,Lombok。step1:Maven依赖<dependencies><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.0</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>jectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>step2:创建实体类//PO:PersistentObject@DatapublicclassArticlePO{privateIntegerid;privateIntegeruserId;privateStringtitle;privateStringsummary;privateIntegerreadCount;privateLocalDateTimecreateTime;privateLocalDateTimeupdateTime;}step3:创建Mapper接口publicinterfaceArticleMapper{Stringfield_list="id,user_id,title,summary,read_count,create_time,update_time";@Insert("""insertintoarticle(user_id,title,summary,read_count,create_time,update_time)\values(#{userId},#{title},#{summary},#{readCount},#{createTime},#{updateTime})""")intinsertArticle(ArticlePOarticle);@Update("""updatearticlesetread_count=#{num}whereid=#{id}""")intupdateReadCount(Integerid,Integernum);@Delete("""deletefromarticlewhereid=#{id}""")intdeleteById(Integerid);@Select("select"+field_list+"fromarticlewhereid=#{articleId}")@Results({@Result(id=true,column="id",property="id"),@Result(column="user_id",property="userId"),@Result(column="read_count",property="readCount"),@Result(column="create_time",property="createTime"),@Result(column="update_time",property="updateTime"),})ArticlePOselectById(@Param("articleId")Integerid);}@Results部分为结果映射(XML中的<ResultMap>),或者用MyBatis的驼峰命名也能实现默认的映射关系。perties#驼峰,下划线命名mybatis.configuration.map-underscore-to-camel-case=truestep4:启动类加入扫描注解@MapperScan({"com.bjpowernode.orm.repository"})@SpringBootApplicationpublicclassLession10MyBatisApplication{publicstaticvoidmain(String[]args){SpringApplication.run(Lession10MyBatisApplication.class,args);}}@MapperScan是扫描注解,参数是Mapper接口所在的包名。参数是数组,可以指定多个包位置。step5:配置数据源perties或yml都可以spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=falsespring.datasource.username=rootspring.datasource.password=123456#驼峰,下划线命名mybatis.configuration.map-underscore-to-camel-case=truestep6:单元测试@SpringBootTestclassLession10MyBatisApplicationTests{@AutowiredprivateArticleMapperarticleMapper;@TestvoidtestInsert(){ArticlePOarticle=newArticlePO();article.setTitle("什么时候用微服务");article.setSummary("微服务优缺点");article.setUserId(219);article.setReadCount(560);article.setCreateTime(LocalDateTime.now());article.setUpdateTime(LocalDateTime.now());articleMapper.insertArticle(article);}@TestvoidtestUpdate(){introws=articleMapper.updateReadCount(1,230);System.out.println("修改的记录数量:"+rows);}@TestvoidtestDelete(){introws=articleMapper.deleteById(11);System.out.println("删除记录的数量"+rows);}@TestvoidtestSelect(){ArticlePOarticlePO=articleMapper.selectById(3);System.out.println("查询到的文章:"+articlePO);}}4.3.2ResultMap查询操作得到包含多个列的集合,将列值转为对象属性使用结果映射的功能,注解@Results,@ResultMap能够帮助我们完成此功能。@Results用于定义结果映射,每个列和Java对象属性的一一对应。@ResultMap指定使用哪个结果映射,两种方式可以使用@Results,另一种XML文件。需求:执行多个select语句,使用结果映射转换数据库记录为JavaObject。step1:创建新的Mapper对象。publicinterfaceArticleDao{//定义mapper,id表示唯一名称@Select("")@Results(id="BaseMapper",value={@Result(id=true,column="id",property="id"),@Result(column="user_id",property="userId"),@Result(column="read_count",property="readCount"),@Result(column="create_time",property="createTime"),@Result(column="update_time",property="updateTime"),})ArticlePOarticleMapper();@Select("""selectid,user_id,title,summary,read_count,create_time,update_timefromarticlewhereuser_id=${userId}""")@ResultMap("BaseMapper")List<ArticlePO>selectList(IntegeruserId);@Select("""selectid,user_id,title,summary,read_count,create_time,update_timefromarticlewhereid=#{articleId}""")@ResultMap("BaseMapper")ArticlePOselectById(@Param("articleId")Integerid);}@Results的id定义当前结果映射的唯一名称,后面内容是列和属性的一一映射说明。其他的查询方法@ResultMap引用@Results的id。使用BaseMapper的映射规则处理查询结果。step2:单元测试@SpringBootTestpublicclassArticleDaoTest{@AutowiredprivateArticleDaoarticleDao;@TestvoidtestSelectList(){List<ArticlePO>poList=articleDao.selectList(219);poList.forEach(po->{System.out.println("po="+po);});}@TestvoidtestSelect(){ArticlePOarticlePO=articleDao.selectById(1);System.out.println("查询到的文章:"+articlePO);}}另一种方法在xml中定义<resultMap>标签,在@ResultMap注解引用。这种方式首先创建xml。在resources目录下创建自定义的mapper目录。新建ArticleMapper.xml。ArticleMapper.xml代码清单:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-////DTDMapper3.0//EN""/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.bjpowernode.orm.repository.ArticleDao"><resultMapid="ArticleMapper"type="com.bjpowernode.orm.po.ArticlePO"><idcolumn="id"property="id"/><resultcolumn="user_id"property="userId"/><resultcolumn="read_count"property="readCount"/><resultcolumn="create_time"property="createTime"/><resultcolumn="update_time"property="updateTime"/></resultMap></mapper>step2:修改perties配置mapper文件的路径mybatis.mapper-locations:自定义mapperxml文件保存路径。spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=falsespring.datasource.username=rootspring.datasource.password=123456#驼峰命名#mybatis.configuration.map-underscore-to-camel-case=truemybatis.mapper-locations=classpath:/mappers/**/*.xmlstep3:修改ArticleDao的查询方法上面的@ResultMap。@Select("""selectid,user_id,title,summary,read_count,create_time,update_timefromarticlewhereid=#{articleId}""")//@ResultMap("BaseMapper")@ResultMap("ArticleMapper")ArticlePOselectById(@Param("articleId")Integerid);在重复执行单元测试代码。4.3.3SQL提供者我们能在方法上面直接编写SQL语句。使用TextBlock编写长的语句。方法上编写SQL显的不够简洁。MyBatis提供了SQL提供者的功能。将SQL以方法的形式定义在单独的类中。Mapper接口通过引用SQL提供者中的方法名称,表示要执行的SQL。SQL提供者有四类@SelectProvider,@InsertProvider,@UpdateProvider,@DeleteProvider。SQL提供者首先创建提供者类,自定义的。类中声明静态方法,方法体是SQL语句并返回SQL。例如:publicstaticStringselectById(){return"SELECT*FROMusersWHEREid=#{id}";}其次Mapper接口的方法上面,应用@SelectProvider(type=提供者类.class,method="方法名称")step1:创建SQL提供者publicclassSqlProvider{publicstaticStringselectArticle(){return"""selectid,user_id,title,summary,read_count,create_time,update_timefromarticlewhereid=#{articleId}""";}publicstaticStringupdateTime(){return"""updatearticlesetupdate_time=#{newTime}whereid=#{id}""";}}step2:创建mapper接口publicinterfaceArticleRepository{@Select("")@Results(id="BaseMapper",value={@Result(id=true,column="id",property="id"),@Result(column="user_id",property="userId"),@Result(column="read_count",property="readCount"),@Result(column="create_time",property="createTime"),@Result(column="update_time",property="updateTime"),})ArticlePOarticleMapper();//查询@ResultMap("BaseMapper")@SelectProvider(type=SqlProvider.class,method="selectArticle")ArticlePOselectById(Integerid);//更新@UpdateProvider(type=SqlProvider.class,method="updateTime")intupdateTime(Integerid,LocalDateTimenewTime);}其他注解@InsertProvider,@DeleteProvider类似的使用方式step3:单元测试@SpringBootTestpublicclassArticleRepositoryTest{@AutowiredprivateArticleRepositoryarticleRepository;@TestvoidtestSelect(){Integerid=2;ArticlePOarticle=articleRepository.selectById(id);System.out.println("article="+article);}@TestvoidtestUpdate(){introws=articleRepository.updateTime(3,LocalDateTime.now());System.out.println("更新的记录数量="+rows);}}我们可以分别创建Insert的提供者,Update提供者,Delete提供者,Select查询者。每个查询者只提供一种操作。Select提供者的方法只提供Select语句。4.3.4@One一对一查询MyBatis支持一对一,一对多,多对多查询。XML文件和注解都能实现关系的操作。我们使用注解表示article和article_detail的一对一关系。MyBatis维护这个关系,开发人员自己也可以维护这种关系。@One:一对一@Many:一对多关系表一个article有一个article_detail文章内容。step1:创建两个表的实体@DatapublicclassArticle{privateIntegerid;privateIntegeruserId;privateStringtitle;privateStringsummary;privateIntegerreadCount;privateLocalDateTimecreateTime;privateLocalDateTimeupdateTime;privateArticleDetailarticleDetail;}@DatapublicclassArticleDetail{privateIntegerid;privateIntegerarticleId;privateStringcontent;}Article声明了ArticleDetail对象。表示文章内容。step2:创建Mapper查询接口publicinterfaceArticleOneToOneMapper{@Select("""selectid,article_id,contentfromarticle_detailwherearticle_id=#{articleId}""")@Results({@Result(id=true,column="id",property="id"),@Result(column="article_id",property="articleId"),@Result(column="content",property="content")})ArticleDetailqueryContent(IntegerarticleId);@Select("""selectid,user_id,title,summary,read_count,create_time,update_timefromarticlewhereid=#{id}""")@Results({@Result(id=true,column="id",property="id"),@Result(column="user_id",property="userId"),@Result(column="read_count",property="readCount"),@Result(column="create_time",property="createTime"),@Result(column="update_time",property="updateTime"),@Result(column="id",property="articleDetail",one=@One(select="com.bjpowernode.orm.repository.ArticleOneToOneMapper.queryContent",fetchType=FetchType.LAZY))})ArticlequeryAllArticle(Integerid);}step3:单元测试@SpringBootTestpublicclassOneToOneTest{@AutowiredprivateArticleOneToOneMapperarticleOneToOneMapper;@TestvoidtestOne(){Articlearticle=articleOneToOneMapper.queryAllArticle(1);System.out.println("article="+article);}}4.3.5@Many一对多查询一对多查询使用@Many注解,步骤与一对一基本相同。准备环境,新建comment评论表。article与comment存在一对多关系。一篇文章多个评论。step1:创建CommentPO实体@DatapublicclassCommentPO{privateIntegerid;privateIntegerarticleId;privateStringcontent;}step2:创建新的文章聚合实体@DatapublicclassArticleEntity{privateIntegerid;privateIntegeruserId;privateStringtitle;privateStringsummary;privateIntegerreadCount;privateLocalDateTimecreateTime;privateLocalDateTimeupdateTime;privateList<CommentPO>comments;//评论的集合}step3:新建Mapper接口publicinterfaceArticleOneToManyMapper{@Select("""selectid,article_id,contentfromcommentwherearticle_id=#{articleId}""")@Results(id="CommentMapper",value={@Result(id=true,column="id",property="id"),@Result(column="article_id",property="articleId"),@Result(column="content",property="content")})List<CommentPO>queryComments(IntegerarticleId);@Select("""selectid,user_id,title,summary,read_count,create_time,update_timefromarticlewhereid=#{id}""")@Results(id="ArticleBaseMapper",value={@Result(id=true,column="id",property="id"),@Result(column="user_id",property="userId"),@Result(column="read_count",property="readCount"),@Result(column="create_time",property="createTime"),@Result(column="update_time",property="updateTime"),@Result(column="id",property="comments",many=@Many(select="com.bjpowernode.orm.repository.ArticleOneToManyMapper.queryComments",fetchType=FetchType.LAZY))})ArticleEntityqueryArticleAndComments(Integerid);}step4:单元测试@SpringBootTestpublicclassOneToManyTest{@AutowiredprivateArticleOneToManyMapperarticleOneToManyMapper;@TestvoidtestOnetoMany(){ArticleEntityarticle=articleOneToManyMapper.queryArticleAndComments(1);System.out.println("ArticleEntity="+article);}}4.3.6常用配置参数MyBatis的项设置,在application文件中“mybatis”开头进行设置。全部设置参考:/mybatis-3/zh/configuration.html#settings常用设置:#驼峰命名mybatis.configuration.map-underscore-to-camel-case=true#mapperxml文件位置mybatis.mapper-locations=classpath:/mappers/**/*.xml#启用缓存mybatis.configuration.cache-enabled=true#延迟加载mybatis.configuration.lazy-loading-enabled=true#mybatis主配置文件,按需使用mybatis.config-location=classpath:/sql-config.xml上述设置内容比较多时,可以将设置放到MyBatis主配置文件,mybatis.config-location加载主配置文件。sql-config.xml<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEconfigurationPUBLIC"-////DTDConfig3.0//EN""/dtd/mybatis-3-config.dtd"><configuration><settings><settingname="cacheEnabled"value="true"/><settingname="lazyLoadingEnabled"value="true"/><settingname="mapUnderscoreToCamelCase"value="true"/></settings><typeAliases><packagename="com.bjpowernode.po"/></typeAliases></configuration>4.3.7MybatisAutoConfigurationMyBatis框架的在SpringBoot的自动配置类MybatisAutoConfiguration.classimports文件中定义了org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration自动配置类@Configuration@ConditionalOnClass({SqlSessionFactory.class,SqlSessionFactoryBean.class})@ConditionalOnSingleCandidate(DataSource.class)@EnableConfigurationProperties({MybatisProperties.class})@AutoConfigureAfter({DataSourceAutoConfiguration.class,MybatisLanguageDriverAutoConfiguration.class})publicclassMybatisAutoConfigurationimplementsInitializingBean{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(MybatisAutoConfiguration.class);privatefinalMybatisPropertiesproperties;.....}关注:MybatisProperties.classDataSourceAutoConfiguration.class,DataSourceProperties.classSqlSessionFactory.classSqlSessionTemplate.class@Bean@ConditionalOnMissingBeanpublicSqlSessionFactorysqlSessionFactory(DataSourcedataSource)throwsException{SqlSessionFactoryBeanfactory=newSqlSessionFactoryBean();factory.setDataSource(dataSource);....}@Bean@ConditionalOnMissingBeanpublicSqlSessionTemplatesqlSessionTemplate(SqlSessionFactorysqlSessionFactory){ExecutorTypeexecutorType=perties.getExecutorType();returnexecutorType!=null?newSqlSessionTemplate(sqlSessionFactory,executorType):newSqlSessionTemplate(sqlSessionFactory);}SqlSessionTemplate是线程安全的,MyBatis为了与Spring继承。提供的由Spring管理的Bean。这个SqlSesionTemplate实现了SqlSession接口,能够由Spring事务管理器使用。提供Spring的事务处理。同时管理SqlSession的创建,销毁。4.4适合的连接池HikariCP连接池/brettwooldridge/HikariCP/wiki连接池配置:/brettwooldridge/HikariCP/wiki/About-Pool-SizingMySQL连接池配置建议/brettwooldridge/HikariCP/wiki/MySQL-ConfigurationprepStmtCacheSize这将设置MySQL驱动程序将缓存每个连接的预准备语句数。默认值为保守的25。我们建议将其设置为250-500之间。prepStmtCacheSqlLimit这是驱动程序将缓存的准备好的SQL语句的最大长度。MySQL默认值为256。根据我们的经验,特别是对于像Hibernate这样的ORM框架,这个默认值远低于生成的语句长度的阈值。我们推荐的设置为2048。cachePrepStmts如果缓存实际上被禁用,则上述参数都没有任何影响,因为默认情况下是禁用的。必须将此参数设置为。trueuseServerPrepStmts:较新版本的MySQL支持服务器端准备语句,这可以提供实质性的性能提升。将此属性设置为。trueapplication.ymlspring:datasource:type:com.zaxxer.hikari.HikariDataSourcedriver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Shanghaiusername:rootpassword:123456hikari:auto-commit:true##connections=((cpu核心数*2)+磁盘数量)近似值。默认10maximum-pool-size:10#最小连接数,默认10,不建议设置。默认与maximum-pool-size一样大小。推荐使用固定大小的连接池minimum-idle:10#获取连接时,检测语句connection-test-query:select1####连接超时,默认30秒。#控制客户端在获取池中Connection的等待时间,#如果没有连接可用的情况下超过该时间,则抛出SQLException异常,###connection-timeout:20000#其他属性data-source-properties:cachePrepStmts:truedataSource.cachePrepStmtst:truedataSource.prepStmtCacheSize:250dataSource.prepStmtCacheSqlLimit:2048dataSource.useServerPrepStmts:true4.5声明式事务事务分为全局事务与本地事务,本地事务是特定于资源的,例如与JDBC连接关联的事务。本地事务可能更容易使用,但有一个显著的缺点:它们不能跨多个事务资源工作。比如在方法中处理连接多个数据库的事务,本地事务是无效的。Spring解决了全局和本地事务的缺点。它允许应用程序开发人员在任何环境中使用一致的编程模型。只需编写一次代码,就可以从不同环境中的不同事务管理策略中获益。Spring框架同时提供声明式和编程式事务管理。推荐声明式事务管理。Spring事务抽象的关键是事务策略的概念,org.springframework.transaction.PlatformTransactionManager接口定义了事务的策略。事务控制的属性:Propagation:传播行为。代码可以继续在现有事务中运行(常见情况),也可以暂停现有事务并创建新事务Isolation:隔离级别。此事务与其他事务的工作隔离的程度。例如,这个事务能看到其他事务未提交的写吗?Timeout超时时间:该事务在超时和被底层事务基础结构自动回滚之前运行的时间。Read-only只读状态:当代码读取但不修改数据时,可以使用只读事务。在某些情况下,例如使用Hibernate时,只读事务可能是一种有用的优化。AOP:SpringFramework的声明式事务管理是通过Spring面向方面编程(AOP)实现的。事务方面的代码以样板的方式使用,及时不了解AOP概念,仍然可以有效地使用这些代码。事务使用AOP的环绕通知(TransactionInterceptor)。声明式事务的方式:XML配置文件:全局配置@Transactional注解驱动:和代码一起提供,比较直观。和代码的耦合比较高。【Spring团队建议您只使用@Transactional注释具体类(以及具体类的方法),而不是注释接口。当然,可以将@Transactional注解放在接口(或接口方法)上,但这只有在使用基于接口的代理时才能正常工作】方法的可见性:公共(public)方法应用@Transactional主机。如果使用@Transactional注释了受保护的、私有的或包可见的方法,则不会引发错误,但注释的方法不会显示配置的事务设置,事务不生效。如果需要受保护的、私有的方法具有事务考虑使用AspectJ。而不是基于代理的机制。4.5.1准备事务演示环境在新的SpringBoot项目演示事务处理。新项目Lession011-Trans。添加MyBatis,MySQL,Lombok依赖。使用之前blog库的article,article_detail表。需求:某个作者发布了新的文章,article,article_detail两个表同时添加记录。需要事务控制两个表的insert操作。step1:创建实体类@DatapublicclassArticlePO{privateIntegerid;privateIntegeruserId;privateStringtitle;privateStringsummary;privateIntegerreadCount;privateLocalDateTimecreateTime;privateLocalDateTimeupdateTime;}//PO:PersistentObject@DatapublicclassArticleDetailPO{privateIntegerid;privateIntegerarticleId;privateStringcontent;}step2:创建Mapper接口,创建两个方法,添加文章属性,文章内容publicinterfaceArticleMapper{@Insert("""insertintoarticle(user_id,title,summary,read_count,create_time,update_time)\values(#{userId},#{title},#{summary},#{readCount},#{createTime},#{updateTime})""")@Options(useGeneratedKeys=true,keyColumn="id",keyProperty="id")intinsertArticle(ArticlePOarticle);@Insert("""insertintoarticle_detail(article_id,content)values(#{articleId},#{content})""")intinsertArticleContent(ArticleDetailPOdetail);}step3:创建Service接口,声明发布文章的方法publicinterfaceArticleService{booleanpostNewArticle(ArticlePOarticle,Stringcontent);}@ServicepublicclassArticleServiceImplimplementsArticleService{@AutowiredprivateArticleMapperarticleMapper;@OverridepublicbooleanpostNewArticle(ArticlePOarticle,Stringcontent){//新增文章articleMapper.insertArticle(article);//新增文章内容ArticleDetailPOdetail=newArticleDetailPO();detail.setArticleId(article.getId());detail.setContent(content);articleMappe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论