1.Spring 中 AOP 的应用场景、Aop 原理、好处? 1
- 源代码无关性 2
2.Spring 中 IOC 的作用与原理?对象创建的过程。 2
3.介绍 spring 框架 2
4.Spring 常见创建对象的注解? 2
5.Spring 中用到的设计模式 2
6.Spring 的优点? 2
7.Spring 管理事务有几种方式? 3
1、编程式事务,在代码中硬编码。(不推荐使用) 3
2、声明式事务,在配置文件中配置(推荐使用) 3
8.spring 中的核心类有那些,各有什么作用? 3
9.什么是 IOC,什么又是 DI,他们有什么区别? 3
10.springMVC 的流程? 3
11.Struts2 的流程? 4
13.springMVC 与 Struts2 的区别? 4
14.如何防止表单重复提交?表单重复提交的原因? 4
2.客户端网络过慢,按钮连续点击。 4
15.hibernate 的优点? 5
16.什么是 Hibernate 延迟加载? 5
17.Hibernate 中一级缓存与二级缓存 5
- Hibernate 二级缓存中存放数据的原则? 5
1 很少被修改的数据 5
2 不是很重要的数据,允许出现偶尔并发的数据 5
3 不会被并发访问的数据 5
4 常量数据 5
1 经常被修改的数据 5
2 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发 5
3 与其他应用共享的数据 5
19.Hibernate 查找对象如何应用缓存? 6
20.Mybatis 的优劣势? 6
21.Mybatis 中一级缓存与二级缓存区别? 6
22.ssm 的优缺点及使用场景。 6
23.Hibernate 和 mybatis 的区别? 7
24.用 spring 怎样实现单例? 8
25.Spring 事务传播机制和数据库隔离级别 8
26.mybatis 如何处理批量插入 8
1.Spring 中 AOP 的应用场景、Aop 原理、好处?
答:AOP 用来封装横切关注点,具体可以在下面的场景中使用:
Authentication 权限、Caching 缓存、Context passing 内容传递、Error handling 错误处理Lazy loading 懒加载、Debugging 调试、logging, tracing, profiling and monitoring 记录跟踪优化校准、Performance optimization 性能优化、Persistence 持久化、Resource pooling 资源池、Synchronization 同步、Transactions 事务
原理:AOP 是面向切面编程,是通过代理的方式为程序添加统一功能,集中解决一些公共问题。
好处:1.各个步骤之间的良好隔离性
- 源代码无关性
2.Spring 中 IOC 的作用与原理?对象创建的过程。
答:当某个角色需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在 spring 中创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由 spring 来完成,然后注入调用者 。
IOC 本质上是一个容器,已 MAP 对 IOC 简单举例,服务器加载配置文件,由 xml 文档解析工具读取 bean 的 ID,获取 class,使用反射创建对象,以 K-V 的形式存入 MAP,K 是 ID,V 是反射创建的对象。获取对象可以调用 context.getBean(K)的方式。
3.介绍 spring 框架
它是一个 full-stack 框架,提供了从表现层到业务层再到持久层的一套完整的解决方案。我们在项目中可以只使用 spring 一个框架,它就可以提供表现层的 mvc 框架,持久层的 Dao框架。它的两大核心 IoC 和 AOP 更是为我们程序解耦和代码简洁易维护提供了支持。
4.Spring 常见创建对象的注解?
答:@Component@Controller@ Service@ Repository
5.Spring 中用到的设计模式
答:简单工厂、工厂方法、单例模式、适配器、包装器、代理、观察者、策略、模板方法
详细介绍:http://www.cnblogs.com/yuefan/p/3763898.html
6.Spring 的优点?
答:1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦
2.可以使用容易提供的众多服务,如事务管理,消息服务等
3.容器提供单例模式支持
4.容器提供了 AOP 技术,利用它很容易实现如权限拦截,运行期监控等功能
5.容器提供了众多的辅助类,能加快应用的开发
6.spring 对于主流的应用框架提供了集成支持,如 hibernate,JPA,Struts 等
7.spring 属于低侵入式设计,代码的污染极低
8.独立于各种应用服务器
9.spring 的 DI 机制降低了业务对象替换的复杂性
10.Spring 的高度开放性,并不强制应用完全依赖于 Spring,开发者可以自由选择 spring的部分或全部
7.Spring 管理事务有几种方式?
答:有两种方式:
1、编程式事务,在代码中硬编码。(不推荐使用)
2、声明式事务,在配置文件中配置(推荐使用)
声明式事务又分为两种:
a、基于 XML 的声明式事务
b、基于注解的声明式事务
8.spring 中的核心类有那些,各有什么作用?
答:BeanFactory:产生一个新的实例,可以实现单例模式
BeanWrapper:提供统一的 get 及 set 方法
ApplicationContext:提供框架的实现,包括 BeanFactory 的所有功能
9.什么是 IOC,什么又是 DI,他们有什么区别?
答:依赖注入 DI 是一个程序设计模式和架构模型, 一些时候也称作控制反转,尽管在技术上来讲,依赖注入是一个 IOC 的特殊实现,依赖注入是指一个对象应用另外一个对象来提供一个特殊的能力,例如:把一个 数据库连接已参数的形式传到一个对象的结构方法里面而不是在那个对象内部自行创建一个连接。控制反转和依赖注入的基本思想就是把类的依赖从类内部转化到外 部以减少依赖
应用控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。也可以说,依赖被注入到对象中。所 以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。
10.springMVC 的流程?
答:Spring MVC的工作原理如下图所示:
① 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。
② DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理该请求的Handler(任何一个对象都可以作为请求的Handler)。
③在这个地方Spring会通过HandlerAdapter对该处理器进行封装。
④ HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用。
⑤ Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。
⑥ ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。
⑦ 当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。
⑧ 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。
11.Struts2 的流程?
① 请求发送给 StrutsPrepareAndExecuteFilter
② StrutsPrepareAndExecuteFilter 判定该请求是否是一个 Struts2 请求
③ 若该请求是一个 Struts2 请求,则 StrutsPrepareAndExecuteFilter 把请求的处理交给
ActionProxy
④. ActionProxy 创建一个 ActionInvocation 的实例,并进行初始化
⑤. ActionInvocation 实例在调用 Action 的过程前后,涉及到相关拦截 器(Intercepter)的
调用。
⑥. Action 执行完毕,ActionInvocation 负责根据 struts.xml 中的配置 找到对应的返回结果。
调用结果的 execute 方法,渲染结果。
⑦. 执行各个拦截器 invocation.invoke() 之后的代码
⑧. 把结果发送到客户端
13.springMVC 与 Struts2 的区别?
答: 1.springmvc 的入口是一个 servlet 即前端控制器,而 struts2 入口是一个 filter 过虑器。
2.springmvc 是基于方法开发(一个 url 对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2 是基于类开发,传递参数是通过类的属性,只能设计为多例。
3.Struts 采用值栈存储请求和响应的数据,通过 OGNL 存取数据, springmvc 通过参数解析器是将 request 请求内容解析,并给方法形参赋值,将数据和视图封装成 ModelAndView对象,最后又将 ModelAndView 中的模型数据通过 reques 域传输到页面。Jsp 视图解析器默认使用 jstl。
14.如何防止表单重复提交?表单重复提交的原因?
答:令牌机制。
原因:1.服务器处理服务后,转发页面,客户端点击刷新(重定向)
2.客户端网络过慢,按钮连续点击。
15.hibernate 的优点?
答:1.对 JDBC 访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2.Hibernate 是一个基于 JDBC 的主流持久化框架,是一个优秀的 ORM 实现。他很大程度的简化 DAO 层的编码工作
3.hibernate 的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。
16.什么是 Hibernate 延迟加载?
答:延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。在 Hibernate 中提供了对实体对象的延迟加载以及对集合的延迟加载,另外在 Hibernate3 中还提供了对属性的延迟加载。
17.Hibernate 中一级缓存与二级缓存
答: Hibernate 缓存包括两大类:Hibernate 一级缓存和 Hibernate 二级缓存
Hibernate 一级缓存又称为“Session 的缓存”,它是内置的,不能被卸载(不能被卸载的意思就是这种缓存不具有可选性,必须有的功能,不可以取消 session 缓存)。由于 Session 对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法卸除。在第一级缓存中,持久化类的每个实例都具有唯一的 OID。
Hibernate 二级缓存又称为“SessionFactory 的缓存”,由于 SessionFactory 对象的生命周期和应用程序的整个过程对应,因此 Hibernate 二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件。需要程序员手动开启。
- Hibernate 二级缓存中存放数据的原则?
答:
适合放到二级缓存中的数据?
1 很少被修改的数据
2 不是很重要的数据,允许出现偶尔并发的数据
3 不会被并发访问的数据
4 常量数据
不适合存放到第二级缓存的数据?
1 经常被修改的数据
2 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
3 与其他应用共享的数据
19.Hibernate 查找对象如何应用缓存?
答:当 Hibernate 根据 ID 访问数据对象的时候,首先从 Session 一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;如果都查不到,再查询数据库,把结果按照 ID 放入到缓存删除、更新、增加数据的时候,同时更新缓存。
20.Mybatis 的优劣势?
答:1. 入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的 SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。
-
可以进行更为细致的 SQL 优化,可以减少查询字段。
-
缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
-
二级缓存机制不佳
21.Mybatis 中一级缓存与二级缓存区别?
答:一级缓存是 SqlSession 级别的缓存。在操作数据库时需要构造 sqlSession 对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的 sqlSession 之间的缓存数据区域(HashMap)是互相不影响的。
一级缓存的作用域是同一个 SqlSession,在同一个 sqlSession 中两次执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个 sqlSession 结束后该 sqlSession 中的一级缓存也就不存在了。Mybatis 默认开启一级缓存。
二级缓存是 mapper 级别的缓存,多个 SqlSession 去操作同一个 Mapper 的 sql 语句,多个 SqlSession 去操作数据库得到数据会存在二级缓存区域,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
二级缓存是多个 SqlSession 共享的,其作用域是 mapper 的同一个 namespace,不同的sqlSession 两次执行相同 namespace 下的 sql 语句且向 sql 中传递参数也相同即最终执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis 默认没有开启二级缓存需要在setting 全局参数中配置开启二级缓存。
22.ssm 的优缺点及使用场景。
答:1.Mybatis 和 hibernate 不同,它不完全是一个 ORM 框架,因为 MyBatis 需要程序员自己编写 Sql 语句,不过 mybatis 可以通过 XML 或注解方式灵活配置要运行的 sql 语句,并将java 对象和 sql 语句映射生成最终执行的 sql,最后将 sql 执行的结果再映射生成 java 对象。
2.Mybatis 学习门槛低,简单易学,程序员直接编写原生态 sql,可严格控制 sql 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是 mybatis 无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql 映射文件,工作量大。
3.Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用 hibernate 开发可以节省很多代码,提高效率。但是Hibernate 的学习门槛高,要精通门槛更高,而且怎么设计 O/R 映射,在性能和对象模型之间如何权衡,以及怎样用好 Hibernate 需要具有很强的经验和能力才行。
总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。
23.Hibernate 和 mybatis 的区别?
答:Hibernate:hibernate 是一个标准的 ORM 框架,不需要写 sql 语句,维护关系比较复杂,sql 语句自动生成,对 sql 语句优化,修改比较困难。
Hibernate 的优缺点:
优点:面向对象开发,不需要自己写 sql 语句。如果进行数据库迁移不需要修改 sql 语句,只需要修改一下方言。
缺点:hibernate 维护数据表关系比较复杂。完全是有 hibernate 来管理数据表的关系,对于我们来说完全是透明的,不易维护。
Hibernate 自动生成 sql 语句,生成 sql 语句比较复杂,比较难挑错。
Hibernate 由于是面向对象开发,不能开发比较复杂的业务。
应用场景:
适合需求变化较少的项目,比如 ERP,CRM 等等
Mybatis 框架对 jdbc 框架进行封装,屏蔽了 jdbc 的缺点,开发简单。
Mybatis 只需要程序员关注 sql 本身,不需要过多的关注业务。对 sql 的优化,修改比较容易
适应场景:适合需求变化多端的项目,比如:互联网项目
NO.1
Hibernate与Mybatis对比总结
两者相同点
· Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。
· Hibernate和MyBatis都支持JDBC和JTA事务处理。
Mybatis优势
· MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
· MyBatis容易掌握,而Hibernate门槛较高。
Hibernate优势
· Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
· Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
· Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
· Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。
NO.2
· Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。
· Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。
· iBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。
· iBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
24.用 spring 怎样实现单例?
答:单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例。
单例模式有以下的特点:
①
单例类只能有一个实例
②
单例类必须自己创建自己的唯一实例
③
单例类必须给所有其他对象提供这一实例
下面我们就来写一个简单的单例模式的例子:
Public class Singleton1{
Private static final Singleton1 instance=new Singleton1();
//私有的默认构造函数
Public Singleton1(){}
//静态工厂方法
Public static Singleton1 getInstance(){
Return instance;
}
}
大家可以看出来,在这个类被加载时,静态变量instance会被初始化,此时该类的私有构造函数被调用,这时候,单例类的唯一实例就被创建出来了
值得注意的是:由于构造函数是私有的,因此该类不能被继承
还有一种写法也可以实现单例模式:
Public class Singleton2{
Private static final Singleton2 instance=null;
//私有的默认构造函数
Public Singleton1(){}
//静态工厂方法
Public synchronized static Singleton2 getInstance(){
If(instance==null){
Instance=new Singleton2();
}
Return instance;
}
}
这种写法和第一种的区别在于:实例并没有直接实例化,而是在静态工厂方法被调用的时候才进行的,而且对静态工厂方法使用了同步化,以处理多线程并发的环境。
这两种写法还有两个非常有意思的名字:第一种称为饿汉式单例,第二种称为懒汉式单例。至于为什么起这个名字,自己好好想想吧。
饿汉式单例在自己被加载时就将自己实例化,如果从资源利用效率角度来讲,比懒汉式单例类稍差些。但是从速度和反应时间角度来讲,则比懒汉式要稍好些。
但是遗憾的是:懒汉式单例类也不能被继承。
我们克服前两种单例类不能被继承的缺点,我们可以使用另外一种特殊化的单例模式,它被称为单例注册表。
Import java.util.HashMap;
Public class RegSingleton{
Static private HashMap registry=new HashMap();
//静态块,在类被加载时自动执行
Static{
RegSingleton rs=new RegSingleton();
Registry.put(rs.getClass().getName(),rs);
}
//受保护的默认构造函数,如果为继承关系,则可以调用,克服了单例类不能为继承的缺点
Protected RegSingleton(){}
//静态工厂方法,返回此类的唯一实例
public static RegSingleton getInstance(String name){
if(name==null){
name=” RegSingleton”;
}if(registry.get(name)==null){
try{
registry.put(name,Class.forName(name).newInstance());
}Catch(Exception ex){ex.printStackTrace();}
}
Return (RegSingleton)registry.get(name);
}
}
下面我们来看看Spring中的单例实现,当我们试图从Spring容器中取得某个类的实例时,默认情况下,Spring会才用单例模式进行创建。
<bean id="date" class="java.util.Date"/>
<bean id="date" class="java.util.Date" scope="singleton"/> (仅为Spring2.0支持)
<bean id="date" class="java.util.Date" singleton="true"/>
以上三种创建对象的方式是完全相同的,容器都会向客户返回Date类的单例引用。那么如果我不想使用默认的单例模式,每次请求我都希望获得一个新的对象怎么办呢?很简单,将scope属性值设置为prototype(原型)就可以了
<bean id="date" class="java.util.Date" scope="prototype"/>
通过以上配置信息,Spring就会每次给客户端返回一个新的对象实例。
那么Spring对单例的底层实现,到底是饿汉式单例还是懒汉式单例呢?呵呵,都不是。Spring框架对单例的支持是采用单例注册表的方式进行实现的,源码如下:
public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{
/**
* 充当了Bean实例的缓存,实现方式和单例注册表相同
*/
private final Map singletonCache=new HashMap();
public Object getBean(String name)throws BeansException{
return getBean(name,null,null);
}
...
public Object getBean(String name,Class requiredType,Object[] args)throws BeansException{
//对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或则做转码)
String beanName=transformedBeanName(name);
Object bean=null;
//手工检测单例注册表
Object sharedInstance=null;
//使用了代码锁定同步块,原理和同步方法相似,但是这种写法效率更高
synchronized(this.singletonCache){
sharedInstance=this.singletonCache.get(beanName);
}
if(sharedInstance!=null){
...
//返回合适的缓存Bean实例
bean=getObjectForSharedInstance(name,sharedInstance);
}else{
...
//取得Bean的定义
RootBeanDefinition mergedBeanDefinition=getMergedBeanDefinition(beanName,false);
...
//根据Bean定义判断,此判断依据通常来自于组件配置文件的单例属性开关
//<bean id="date" class="java.util.Date" scope="singleton"/>
//如果是单例,做如下处理
if(mergedBeanDefinition.isSingleton()){
synchronized(this.singletonCache){
//再次检测单例注册表
sharedInstance=this.singletonCache.get(beanName);
if(sharedInstance==null){
...
try {
//真正创建Bean实例
sharedInstance=createBean(beanName,mergedBeanDefinition,args);
//向单例注册表注册Bean实例
addSingleton(beanName,sharedInstance);
}catch (Exception ex) {
...
}finally{
...
}
}
}
bean=getObjectForSharedInstance(name,sharedInstance);
}
//如果是非单例,即prototpye,每次都要新创建一个Bean实例
//<bean id="date" class="java.util.Date" scope="prototype"/>
else{
bean=createBean(beanName,mergedBeanDefinition,args);
}
}
...
return bean;
}
}
25.Spring 事务传播机制和数据库隔离级别
答:http://www.cnblogs.com/sxl525blogs/p/3674834.html
26.mybatis 如何处理批量插入
答:在程序中封装了一个List集合对象,然后需要把该集合中的实体插入到数据库中,由于项目使用了Spring+MyBatis的配置,所以打算使用MyBatis批量插入,由于之前没用过批量插入,在网上找了一些资料后最终实现了,把详细过程贴出来。
实体类TrainRecord结构如下:
Java代码 收藏代码
public class TrainRecord implements Serializable {
private static final long serialVersionUID = -1206960462117924923L;
private long id;
private long activityId;
private long empId;
private int flag;
private String addTime;
//setter and getter
}
对应的mapper.xml中定义如下:
Xml代码 收藏代码
<resultMap type="TrainRecord" id="trainRecordResultMap">
<id column="id" property="id" jdbcType="BIGINT" />
<result column="add_time" property="addTime" jdbcType="VARCHAR" />
<result column="emp_id" property="empId" jdbcType="BIGINT" />
<result column="activity_id" property="activityId" jdbcType="BIGINT" />
<result column="flag" property="status" jdbcType="VARCHAR" />
</resultMap>
mapper.xml中批量插入方法的定义如下:
Xml代码 收藏代码
<insert id="addTrainRecordBatch" useGeneratedKeys="true" parameterType="java.util.List">
<selectKey resultType="long" keyProperty="id" order="AFTER">
SELECT
LAST_INSERT_ID()
</selectKey>
insert into t_train_record (add_time,emp_id,activity_id,flag)
values
<foreach collection="list" item="item" index="index" separator="," >
(#{item.addTime},#{item.empId},#{item.activityId},#{item.flag})
</foreach>
</insert>
对于foreach标签的解释参考了网上的资料,具体如下:
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有 item,index,collection,open,separator,close。item表示集合中每一个元素进行迭代时的别名,index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔 符,close表示以什么结束,在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下3种情况:
1.如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
2.如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
3.如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map
关于foreach的具体例子在这里就先不举,以后有机会可以把每一种情况都举一个例子列出来。
MysqlBaseDAO:
Java代码 收藏代码
public class MySqlBaseDAO extends SqlSessionDaoSupport {
/**
* insert:插入操作. <br/>
*
* @author chenzhou
* @param method 插入操作的方法名
* @param entity 查询参数或实体类
* @return 返回影响的行数
* @since JDK 1.6
*/
public int insert(String method,Object entity){
return this.getSqlSession().insert(method, entity);
}
//其余方法省略
}
TrainRecord实体类对应的TrainRecordDAO 定义如下:
Java代码 收藏代码
public class TrainRecordDAO extends MySqlBaseDAO {
/**
* addTrainRecordBatch:批量插入培训记录. <br/>
*
* @author chenzhou
* @param trainRecordList 培训记录list集合
* @return 影响的行数
* @since JDK 1.6
*/
public int addTrainRecordBatch(List<TrainRecord> trainRecordList){
return this.insert("addTrainRecordBatch", trainRecordList);
}
//省略其余的方法
}
然后直接调用TrainRecordDAO 中的 addTrainRecordBatch方法就可以批量插入了。
特别说明的是在尝试时碰到了一个让人无语的错误,折腾了我差不多1个小时才解决。就是我在定义mapper.xml中的插入方法时一般都会默认用<![CDATA[ ]]>标签把sql语句括起来,如下所示:
Xml代码 收藏代码
<![CDATA[
select * from t_train_record t where t.activity_id=#{activityId}
]]>
这样做的目的主要是因为在 XML 元素中,"<" 和 “&” 是非法的。"<" 会产生错误,因为解析器会把该字符解释为新元素的开始。"&" 也会产生错误,因为解析器会把该字符解释为字符实体的开始。而sql语句或者脚本语句中可能会存在 “<” 或 “&” 字符。为了避免错误,可以将sql语句定义为 CDATA。CDATA 部分中的所有内容都会被解析器忽略。
当时我在addTrainRecordBatch方法中也用了这种用法:
Xml代码 收藏代码
<![CDATA[
insert into t_train_record (add_time,emp_id,activity_id,flag)
values
<foreach collection="list" item="item" index="index" separator="," >
(#{item.addTime},#{item.empId},#{item.activityId},#{item.flag})
</foreach>
]]>
结果程序在执行时老是报错: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException,查看错误信息就是传入的参数都是null。纠结了很久,后面才发现原来是<![CDATA[ ]]>把xml中的标签括起来后把标签直接当成字符串处理了。后面把外面的<![CDATA[ ]]>去掉后就能正常执行了。