`
lihuiqi_cn
  • 浏览: 26247 次
  • 性别: Icon_minigender_2
  • 来自: 河北
社区版块
存档分类
最新评论

SpringSide 3 中的数据库访问层和单元测试用例

 
阅读更多

在SpringSide 3 中,数据库访问层使用的是Hibernate,Hibernate是一个很优秀的ORM框架,是大家耳熟能详的东西了。关于Hibernate的内容,很多人是写了又写,我想我是很难写出新意了。不过我的思路是这样的,我从实际开发的过程出发,写出在SpringSide 3中使用Hibernate的步骤,在这些步骤中,探讨SpringSide 3对Hibernate的封装,探讨数据持久层的单元测试,探讨二级缓存和性能优化。

我创建一个虚拟的应用场景来做示范,假设我们开发的是一个简单的文章发布系统,实现对文章简单的增删查改功能。同时为了演示多个表之间的关联查询,假设每篇文章有多篇评论。这时,我们需要在数据库中创建两个表,如下:

create   table  articles(
id 
int   primary   key  auto_increment,
subject 
varchar ( 20 not   null ,
content 
text );

create   table  comments(
id 
int   primary   key  auto_increment,
content 
varchar ( 255 ),
article_id 
int   not   null ,
foreign   key  (article_id)  references  articles(id)
);


我的开发习惯是先写数据库Schema,再写Hibernate的Entity类,再写DAO类,最后在Action里面使用DAO类。这只是我个人的习惯,大家都知道,Hibernate有通过Entity类自动生成数据库Schema的工具,这说明很多人习惯先写Entity类而不关注数据库的细节。但是我从没有用过这样的工具,我喜欢了解数据库的细枝末节,所以我总是自己写数据库Schema。

在MySQL的客户端直接执行上面的SQL语句就可以创建这两个表了。这里需要额外提一下的是我使用的数据库是MySQL,而不是默认的Derby,要把SpringSide创建的项目的数据库更换为MySQL并不难,只需要如下几个步骤:
1、更改数据库地址、用户名、密码(MySQL需要在数据库地址中指定UTF-8编码);
2、更改数据库驱动、Dialect,同时,需要自己下载MySQL的JDBC驱动放到项目中;
3、SQL文件,因为Derby的语法和MySQL的有点不一样,比如MySQL中就应该使用AUTO_INCREMENT,而不是GENERATED ALWAYS as IDENTITY,并且Drop数据表的时候,MySQL可以加上IF EXISTS选项。

下一步,编写Entity类:

package  cn.puretext.entity.web;

import  java.util.LinkedHashSet;
import  java.util.Set;

import  javax.persistence.CascadeType;
import  javax.persistence.Entity;
import  javax.persistence.JoinColumn;
import  javax.persistence.OneToMany;
import  javax.persistence.OrderBy;
import  javax.persistence.Table;

import  org.hibernate.annotations.Cache;
import  org.hibernate.annotations.CacheConcurrencyStrategy;
import  org.hibernate.annotations.Fetch;
import  org.hibernate.annotations.FetchMode;

import  cn.puretext.entity.IdEntity;

@Entity
//  表名与类名不相同时重新定义表名.
@Table(name  =   " articles " )
//  默认的缓存策略.
@Cache(usage  =  CacheConcurrencyStrategy.READ_WRITE)
public   class  Article  extends  IdEntity {
    
private  String subject;
    
private  String content;
    
private  Set < Comment >  comments  =   new  LinkedHashSet < Comment > ();
    
    
public  String getSubject() {
        
return  subject;
    }

    
public   void  setSubject(String subject) {
        
this .subject  =  subject;
    }

    
public  String getContent() {
        
return  content;
    }

    
public   void  setContent(String content) {
        
this .content  =  content;
    }

    @OneToMany(cascade 
=  { CascadeType.ALL })
    @JoinColumn(name 
=   " article_id " )
    
//  Fecth策略定义
    @Fetch(FetchMode.SUBSELECT)
    
//  集合按id排序.
    @OrderBy( " id " )
    
//  集合中对象id的缓存.
    @Cache(usage  =  CacheConcurrencyStrategy.READ_WRITE)
    
public  Set < Comment >  getComments() {
        
return  comments;
    }

    
public   void  setComments(Set < Comment >  comments) {
        
this .comments  =  comments;
    }
}

package  cn.puretext.entity.web;

import  javax.persistence.Entity;
import  javax.persistence.Table;

import  org.hibernate.annotations.Cache;
import  org.hibernate.annotations.CacheConcurrencyStrategy;

import  cn.puretext.entity.IdEntity;

@Entity
//  表名与类名不相同时重新定义表名.
@Table(name  =   " comments " )
//  默认的缓存策略.
@Cache(usage  =  CacheConcurrencyStrategy.READ_WRITE)
public   class  Comment  extends  IdEntity {
    
private  String content;
    
    
public  String getContent() {
        
return  content;
    }

    
public   void  setContent(String content) {
        
this .content  =  content;
    }
}


通过上面的代码,大家可以注意到如下的信息:
1、上面的Entity类都没有了id,为什么呢?因为白衣把它抽出来了,做了一个IdEntity基类让我们继承,所以,以后只要是数据库中含有id的表,编写Entity类的时候都可以从IdEntity继承。
2、 Entity中使用的Annotation就不用多说了,JPA Annotation已经不是什么新东西,在上面的Entity中,我演示了一下@OneToMany,而白衣在项目里面大量演示了 @ManyToMany,我以前写的一篇博文《打通数据持久层的任督二脉》中讨论了@OneToOne和@ManyToOne,这回算是补齐了。
3、上面的Entity中涉及到了抓取策略和缓存策略,使用注解设置起来也很简单。

下一步,编写DAO类:

package  cn.puretext.dao;

import  org.springframework.stereotype.Repository;
import  org.springside.modules.orm.hibernate.HibernateDao;

import  cn.puretext.entity.web.Article;

@Repository
public   class  ArticleDao  extends  HibernateDao < Article, Long >  {

}


可以看到该类非常之简单,原因嘛,自然是因为SpringSide的基类做了大量的工作。这这里,该DAO类的继承层次是这样的:


从截图中可以看出,SpringSide提供了HibernateDao和SimpleHibernateDao两个基类,在这两个基类中,封装了CRUD 操作,而HibernateDao类更提供了分页查询函数。这个封装的思路和前一代的SpringSide是一样的,但是有几个区别:
1、可以不创建自己的DAO类,什么意思呢?举例说明,上面为Article创建了ArticleDao类,那么在Action中可以这样用:
ArticleDao articleDao = new ArticleDao();(这只是一个示范,事实上不需要显示创建,因为在SpringSide 3中,靠的都是注入)
但是也可以不要ArticleDao,而直接这样用:
HibernateDao articleDao = new HibernateDao();
这样做有什么好处呢?当然是可以有效减少Dao层类的数量,如果有的Dao类使用得比较少,那么就没有必要专门为它创造一个Dao类了。

写到这里,我又忍不住要评论一下江南白衣在项目架构方面的一些习惯了,他的层次太多,这应该是他在实际项目中锤炼出来的经验,但是和教科书上的就不大一样了,教科书上的三层就是三层,而白衣可以把它扩展到4层甚至5层,白衣的层次可以总结成 Entity->DAO->Service(Manager)->Action->View,其中Service这一层命名还不统一,包名是Service,类名中用的是Manager。我觉得这个大家可以探讨探讨,也许白衣认为DAO里面不应该包含业务逻辑,只应该包含CRUD 和分页操作,而Action里面也不应该包含业务逻辑,所以就单独抽出一层来了吧,所以这一层应该称为Bussiness层比较合适,而白衣也认为,有时候DAO层和Bussiness层可以合并在一起。另外,我认为白衣在项目中搞的package也太多了一点,在IDE里面不方便,所以我的实际项目中,我会对包重新进行整理。

2、在DAO类中可以使用Hibernate的原生API。我们来总结一下在Hibernate中通常采用的查询方式:一是使用HQL语言,它的过程基本上是先获取Session,然后创建Query对象,最后通过Query对象执行HQL语句;二是使用条件查询,它的过程基本上是先获取 Session,然后创建Creteria对象,然后执行Creteria对象的list()方法。而在Dao类中,我们可以很简单的通过 sessionFactory.getCurrentSession()来获得Session对象,进而很方便的使用到HQL或者Creteria。

3、在SpringSide 2中,我们可以对数据表中的数据不做物理删除,该特性得益于白衣提供的@Undeletable注解和HibernateEntityExtendDao 类,在SpringSide 3中,该特性没有了。现在回想起来,我觉得该特性也没有什么存在的必要。

后面再继续探讨分页查询和性能优化。现在的任务是赶紧确认一下这Entity层和Dao层能否正常工作,完成该任务的最佳途径,当然是单元测试了。

在SpringSide 3中,编写单元测试非常方便,只需要继承白衣提供的SpringContextTestCase类或者SpringTxTestCase类即可,事实上,只有继承SpringTxTestCase类才能正常工作,因为我们的项目的配置无法让我们工作在非事务的环境下。继承这个类有什么用处呢?它的用处就是可以读取项目中的applicationContext.xml文件,自动建立数据源、Dao对象,并把Dao对象注入到测试用例中,所以,测试类的代码非常简洁,如下:

package  cn.puretext.unit.service;

import  java.util.List;

import  org.junit.Test;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springside.modules.orm.Page;
import  org.springside.modules.test.junit4.SpringTxTestCase;

import  cn.puretext.dao.ArticleDao;
import  cn.puretext.entity.web.Article;

public   class  DaoTest  extends  SpringTxTestCase {
    @Autowired
    
private  ArticleDao articleDao;

    
public  ArticleDao getArticleDao() {
        
return  articleDao;
    }

    
public   void  setArticleDao(ArticleDao articleDao) {
        
this .articleDao  =  articleDao;
    }

    @Test
    
public   void  addArticle() {
        Article article 
=   new  Article();
        article.setSubject(
" article test " );
        article.setContent(
" article test " );
        articleDao.save(article);
    }
}

因为该单元测试工作在事务环境下,所以运行单元测试不会改变数据库中的数据。白衣提供的这两个类事实上只是在Spring 2.5的测试框架上做了一点点改进。关于Spring 2.5测试框架的详细介绍,大家可以到“IBM DeveloperWorks 中国”上去看这一篇文章:
http://www.ibm.com/developerworks/cn/java/j-lo-spring25-test/

但是白衣自己的做法却完全不同,在白衣写的单元测试中,他偏偏用的是EasyMock,关于EasyMock的使用方法,大家可以到“IMB DeveloperWorks 中国”上去看这一篇文章:
http://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/

再让大家看一下截图,我特地把测试类的代码、JUnit著名的绿条和Hibernate输出的SQL语句放到了一起,如下:

代码比较简单,只是为了证明上面写的Entity和Dao能够正常运行。在下面的内容里,随着我们的探讨,测试代码的内容会逐渐增加。

上文的内容演示了SpringSide 3中Hibernate的使用过程和单元测试,也提到了SpringSide 3提供的CRUD封装,这些都很简单。在SpringSide 3对Hibernate的封装中,还有一个重点,那就是分页查询。

分页查询有HibernateDao类实现,要配合Page类来使用。Page类一般用来设置查询条件,并返回查询结果,举例说明,如果对Articles表中的数据进行分页显示,每一页10条记录,那么查询第二页应该怎么办呢?代码如下:

@Test
 
public   void  pageQuery() {
  Page
< Article >  page  =   new  Page < Article > ();
  page.setPageSize(
10 );
  page.setPageNo(
2 );
  page 
=  articleDao.getAll(page);
  List
< Article >  articles  =  page.getResult();
 }


以上代码在单元测试中进行,这个过程很容易理解,就是先创建一个Page对象,然后设置该页的大小和序号,就可以直接查找该页的数据了。同时,Page类还有很多辅助方法,如获取总的记录条数,获取页的总数,获取是否有下一页等等。

Page只是一个辅助类,真正的查询操作是在HibernateDao类中完成的,具体代码如下:

/**
  * 按Criteria分页查询.
  * 
  * 
@param  page 分页参数.
  * 
@param  criterions 数量可变的Criterion.
  * 
  * 
@return  分页查询结果.附带结果列表及所有查询时的参数.
  
*/
 @SuppressWarnings(
" unchecked " )
 
public  Page < T >  find( final  Page < T >  page,  final  Criterion criterions) {
  Assert.notNull(page, 
" page不能为空 " );

  Criteria c 
=  createCriteria(criterions);

  
if  (page.isAutoCount()) {
   
int  totalCount  =  countCriteriaResult(c);
   page.setTotalCount(totalCount);
  }

  setPageParameter(c, page);
  List result 
=  c.list();
  page.setResult(result);
  
return  page;
 }


可以看到,白衣的实现用的是Hibernate中的条件查询,从上面的代码可以看出,该过程是先创建Criteria对象,然后查询记录的总数,并将记录的总数填入到Page对象中,然后再调用setPageParameter方法将Page对象中的信息填入到Criteria对象中,最后调用Criteria对象的list()方法来获取结果。

下面跟踪到setPageParameter方法中,其代码如下:

  protected  Criteria setPageParameter( final  Criteria c,  final  Page < T >  page) {
  
// hibernate的firstResult的序号从0开始
  c.setFirstResult(page.getFirst()  -   1 );
  c.setMaxResults(page.getPageSize());
  
/* 以下代码省略 */
}


可以看到,该方法中只是简单地调用了Criteria对象的setFirstResult和setMaxResults方法,这都是Hibernate的原生API,没有什么需要特殊说明的。我比较关心的是分页查询所生成的SQL语句及其正确性。

讲到这里,我得提一下我的技术背景:在使用MySQL之前,我有很长一段时间使用的是MS SQL Server 2000。为什么要提这个问题呢?那是因为站在SQL Server 2000的角度,处理分页问题是比较困难的。在SQL Server 2000中,如果要获取指定条数的记录,只能使用top关键字,也就是说要获取10条数据,就应该使用select * top 10 from articles,那么怎么定位到第二页呢?就必须知道第二页的第一条数据的ID是多少,然后用这样的语句select * top 10 from articles where id >= ?,那怎么知道第二页的第一条记录的ID是多少呢?免不了又要多一次查询如select id top 20 from articles order by id desc。

所以在SQL Server 2000中,要实现分页查询比较困难,不是思考起来困难,而是提高效率困难,必须得避免多次查询。解决的办法当然有,要么使用存储过程,要么在前面的select语句中加入子查询。但是不管采取哪种办法,SQL语句写起来都不简单。

在MySQL中,该问题就简单多了,MySQL不提供top,但提供limit,更重要的是limit接受两个参数,而不是像top只接受一个参数。limit后面的参数可以是{[offset,] row_count | row_count OFFSET offset},其中的offset就代表了第2页的第一条数据所在的位置,大家请注意,这里说的是位置,而不是SQL Server 2000中的ID,这两者是有区别的,因为ID可能不连续,而位置肯定是连续的,所以位置是可以通过简单的数学计算来获得的,这样,MySQL就只需要生成一个简单的SQL语句select * from articles limit 10,10。

下面是Hibernate自己生成的SQL语句:
    select
        this_.id as id4_0_,
        this_.content as content4_0_,
        this_.subject as subject4_0_
    from
        articles this_ limit ?,
        ?

为了和SQL Server 2000对比,我把配置文件中的Dialect改为org.hibernate.dialect.SQLServerDialect,得到的SQL语句如下:
    select
        top 20 this_.id as id4_0_,
        this_.content as content4_0_,
        this_.subject as subject4_0_
    from
        articles this_
2009-07-09 22:22:53,950 [main] WARN  [org.hibernate.util.JDBCExceptionReporter] - SQL Error: 1064, SQLState: 42000
2009-07-09 22:22:53,969 [main] ERROR [org.hibernate.util.JDBCExceptionReporter] - You have an error in your SQL syntax;

因为我没有把数据库迁移到SQL Server,所以该语句一运行就出错了,不过从该语句中的top 20也可以看出,要么该语句的作用是为了得到第二页的第一条记录的ID,然后后面再跟一条SQL语句,只不过因为出现错误,所以后面的语句没有显示出来,要么是直接取出20条记录,并抛弃10条,只留下第二页的数据。总之,和我之前预想的一样,性能得不到保证。

通过搜索引擎我还查出,Oracle也不支持limit语句,所以说,我们不能完全相信Hibernate,必要的时候,还是得靠自己写存储过程。

Fetch策略也是影响性能的一个方面,Fetch策略主要是针对Entity中的集合数据,正如白衣所说,很多人多只知道使用默认的Lazy策略,我就是这很多人中的一个,以前我还因为Lazy策略出现过问题,什么问题呢,那就是我先获取一个Entity的数据,然后把在Entity保存到 HttpSession中,然后在使用该对象中的集合数据时,就报错了,为什么呢,因为这个时候Hibernate的Session早就关闭了,所以出错。

关于Fetch策略的选择,SpringSide的文档和Hibernate的文档上面都写得很清楚,我就不罗嗦了,至于在代码中怎么设置Fetch策略,代码的注释很清楚,一看就会。

最后谈一谈二级缓存,Session中的缓存是一级缓存,ehcache提供二级缓存,关于二级缓存的配置,主要涉及到两个地方,一个是xml配置文件,另一个是Entity类中的注解,xml配置文件中配置的是ehcache的属性,而Entity中的注解设置了隔离级别,具体内容请参阅 SpringSide 3 的文档。

分享到:
评论
1 楼 hsjshijiazhuang 2011-12-07  
关注。。。

相关推荐

    springside全攻略

    JUnit和Mockito等工具被用来编写和执行测试用例,保证代码质量。同时,SpringSide支持与Jenkins等持续集成工具的集成,实现自动化构建和部署。 九、示例项目 在"springside"这个压缩包文件中,包含了各种示例项目的...

    springside

    7. **单元测试与集成测试**:SpringSide提供了丰富的测试支持,使用JUnit进行单元测试,使用Mockito进行模拟对象测试,以及使用DBUnit进行数据库相关的集成测试。源码中包含了这些测试用例,有助于理解如何在Spring...

    springside3.0.4.all.in.one.zip

    在这个项目中,它主要负责与MySQL数据库的交互,实现数据访问层(DAO)功能。通过使用MySQL Connector/J,开发者可以方便地执行SQL查询语句、更新数据等操作。 #### Commons Logging 1.0.4 Commons Logging是一个...

    Spring+Hibernate+Jpa+Struts2整合实例

    5. **整合测试**:编写测试用例,验证Spring、Hibernate、JPA和Struts2的整合是否正常工作,包括数据库的存取、业务逻辑的执行以及视图的展示。 在提供的压缩包文件中,我们看到了以下几个关键的库文件: - `...

    基于A*算法的往返式全覆盖路径规划改进及其Matlab实现

    内容概要:本文详细介绍了如何利用A*算法改进传统的往返式路径规划,解决扫地机器人在复杂环境中容易卡住的问题。首先构建了一个可视化的栅格地图用于模拟环境,然后引入了优先级运动规则,使机器人能够有规律地进行往返清扫。当遇到死角时,通过A*算法计算最佳逃生路径,确保机器人能够顺利脱困并继续完成清扫任务。实验结果显示,改进后的算法显著提高了清洁覆盖率,降低了路径重复率。此外,还讨论了一些潜在的优化方向,如动态调整启发函数权重、断点续传以及能耗模型等。 适合人群:对路径规划算法感兴趣的科研人员、自动化专业学生、扫地机器人开发者。 使用场景及目标:适用于需要高覆盖率和低重复率的室内清洁任务,旨在提高扫地机器人的工作效率和智能化水平。 其他说明:文中提供了详细的Matlab代码实现,并附带了仿真测试结果,有助于读者理解和复现该算法。

    爬取喜马拉雅听书(1).py

    爬取喜马拉雅听书(1)

    安卓向上传递数据学习笔记总结

    安卓向上传递数据学习笔记总结

    tigervnc-selinux-1.11.0-9.el8.x64-86.rpm.tar.gz

    1、文件说明: Centos8操作系统tigervnc-selinux-1.11.0-9.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf tigervnc-selinux-1.11.0-9.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm

    户外储能电源双向逆变器板生产资料及技术规格详解

    内容概要:本文详细介绍了户外储能电源双向逆变器板的技术资料及其特点。涵盖原理文件、PCB文件、源代码、电感与变压器规格参数等,适用于2KW(最大3KW)的户外储能电源。文中强调了双向软开关DC-DC设计、两颗M0+ 32位MCU的分工、SPWM调制方式、H桥IGBT的应用、详细的电气参数和技术特性。此外,还包括了SPWM信号生成代码示例、硬件设计细节、生产注意事项等。 适合人群:从事户外储能电源开发的技术人员、电子工程师、产品经理等。 使用场景及目标:帮助开发者快速掌握双向逆变器板的设计和生产要点,缩短产品研发周期,提高产品质量和可靠性。具体应用场景包括但不限于户外应急电源、便携式储能设备等。 其他说明:本文提供了丰富的技术细节和实践经验,如双向软开关DC-DC设计、SPWM调制、IGBT驱动、EMC整改记录等,有助于解决实际开发中的难题。同时,附带的实际案例展示了该方案的成功应用,进一步证明了其可行性和优越性。

    电能质量分析:间谐波分析.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    【计算机科学领域】美国计算机学会(ACM):组织架构、使命愿景、核心价值及活动项目介绍

    内容概要:美国计算机学会(ACM)是一个成立于1947年的国际性计算机专业组织,致力于推动计算机科学的发展,提供教育、资源和专业发展机会。ACM的使命是促进计算机科学和信息技术领域的进步,愿景是成为全球计算机专业人士的首选组织。其核心价值包括卓越、诚信、包容性、合作和创新。ACM定期举办学术会议,如SIGGRAPH和图灵奖颁奖典礼,出版高质量的学术期刊和会议论文集,涵盖人工智能、软件工程、网络安全等领域。此外,ACM还提供在线课程、研讨会、认证项目等教育资源,以及职业规划、网络机会和领导力培训等职业发展服务。ACM图灵奖被誉为“计算机界的诺贝尔奖”,每年颁发给对计算机科学和技术做出重大贡献的个人。; 适合人群:计算机科学领域的专业人士、教育工作者、工程师和学生。; 使用场景及目标:①了解计算机科学领域的最新研究成果和发展趋势;②获取高质量的教育资源和职业发展机会;③参与计算机科学领域的学术交流和合作。; 其他说明:ACM作为一个全球性的组织,在教育、研究和行业实践中发挥着重要作用,推动了技术创新和社会进步。

    最新版logstash-8.17.4-windows-x86-64.zip

    logstash-8.17.4-windows-x86_64.zip

    一个基于Springboot使用Aspect实现一个切面,以记录日志为例

    springboot 一个基于Springboot使用Aspect实现一个切面,以记录日志为例

    音箱底部折边设备sw22可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    音箱底部折边设备sw22可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    基于Python Django MySQL的个性化图书推荐系统:协同过滤算法及远程部署实现

    内容概要:本文详细介绍了如何使用Python、Django和MySQL构建一个完整的个性化图书推荐系统。系统从前端界面设计、后端逻辑实现到数据库设计,涵盖了用户管理、图书管理、评分系统等功能模块。重点讲解了基于用户和项目的协同过滤算法实现,以及在用户评分数据不足时的标签推荐备份方案。此外,还包括了系统部署、测试和优化的具体步骤,如云服务器部署、性能测试、数据库优化等。 适合人群:具备一定Python和Web开发基础的研发人员,尤其是对推荐系统感兴趣的技术爱好者。 使用场景及目标:适用于希望深入了解图书推荐系统的工作原理和实现细节的技术人员。目标是帮助读者掌握从零开始搭建一个完整的个性化推荐系统的方法,包括前后端开发、算法实现和系统部署。 其他说明:文中提供了大量代码示例和实战经验,如数据库设计、爬虫实现、权限管理等,有助于读者更好地理解和应用相关技术。

    Ai和python学习资料

    Ai和python学习资料

    文本摘要.py

    文本摘要

    冲击试验机sw22_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    冲击试验机sw22_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    Java开发MybatisPlus框架详解:增强Mybatis功能实现高效CRUD操作与代码生成

    内容概要:本文详细介绍了MyBatis Plus(MP),它是MyBatis的增强工具,旨在简化CRUD操作、提高开发效率。其主要功能包括内置分页插件、简化CRUD操作以及代码生成器。使用时只需引入相应依赖,自定义Mapper接口继承BaseMapper泛型接口,并通过实体类反射获取数据库表信息。文章还介绍了常用注解如@TableName、@TableId、@TableField、@TableLogic和@Version,配置项如全局配置、类型别名和Mapper文件路径,以及核心功能如批量插入、分页查询、条件构造器(Wrapper)等。此外,扩展功能涵盖逻辑删除、枚举处理器和JSON处理器,插件功能则包括分页插件的配置和使用。 适合人群:具备一定Java开发经验,尤其是熟悉MyBatis框架的开发者,特别是那些希望提高开发效率、减少重复代码的工作1-3年研发人员。 使用场景及目标:①简化数据库操作,提高开发效率;②快速生成代码,减少手动编写SQL语句的工作量;③实现分页查询、逻辑删除、枚举和JSON字段处理等高级功能,提升应用的灵活性和可维护性。 其他说明:本文不仅提供了MyBatis Plus的功能介绍和使用方法,还深入探讨了条件构造器(Wrapper)的使用技巧,帮助开发者更好地理解和掌握这一强大的工具。在实际开发中,合理利用这些功能可以显著提高开发效率和代码质量。建议在学习过程中结合具体项目实践,逐步掌握各个功能的应用场景和最佳实践。

    电路仿真:射频电路仿真.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

Global site tag (gtag.js) - Google Analytics