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

阶梯式使用SpringMVC+MyBatis

2013-04-08 22:40 387 查看
概述

        对于SpringMVC的使用,上一篇文章已经做了说明,并上传了Demo,大家可以下载下来练习指教。这篇文章将由浅入深的集成MyBatis,并给出可以运行的Code。

 

MyBatis基础条件

        下载MyBatis开发包,将其核心包和lib下所有包拷贝到项目lib目录,这些包在之后都会用到,同时添加到classpath下。下载地址为:http://code.google.com/p/mybatis/

         在ClassPath(src目录)下添加MyBatis基础配置文件,名称可自定义,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<!--声明数据库方言为Mysql-->
<properties>
<property name="dialect" value="mysql"/>
</properties>
<settings>
<!-- 这个配置使全局的映射器启用或禁用缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 允许或不允许多种结果集从一个单独的语句中返回(需要适合的驱动) -->
<setting name="multipleResultSetsEnabled" value="true"/>
<!-- 使用列标签代替列名。不同的驱动在这方便表现不同。参考驱动文档或充分测试两种方法来决定所使用的驱动 -->
<setting name="useColumnLabel" value="true"/>
<!-- 允许JDBC支持生成的键。需要适合的驱动。如果设置为true则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如Derby) -->
<setting name="useGeneratedKeys" value="true"/>
<!-- 指定MyBatis如何自动映射列到字段/属性。PARTIAL只会自动映射简单,没有嵌套的结果。FULL会自动映射任意复杂的结果(嵌套的或其他情况) -->
<setting name="autoMappingBehavior" value="FULL"/>
<!-- 配置默认的执行器。SIMPLE执行器没有什么特别之处。REUSE执行器重用预处理语句。BATCH执行器重用语句和批量更新 -->
<setting name="defaultExecutorType" value="SIMPLE"/>
<!-- 设置超时时间,它决定驱动等待一个数据库响应的时间 -->
<setting name="defaultStatementTimeout" value="25000"/>
</settings>
<!--为实体类指定别名-->
<typeAliases>
<typeAlias type="entity.Archives" alias="archive"/>
<typeAlias type="entity.Student" alias="student"/>
<typeAlias type="entity.Teacher" alias="teacher"/>
<typeAlias type="entity.School" alias="school"/>
</typeAliases>
<!--分页会用到-->
<plugins>
<plugin interceptor="Interceptor.PaginationInterceptor"></plugin>
</plugins>
</configuration>

 

配置数据源

       本文在tomcat中配置数据源,并通过Spring的Jndi方式lookup数据源,步骤如下:找到tomcat安装目录下conf目录,打开server.xml,在host节点中加入如下内容:

<Context docBase="SpringMVC" path="/SpringMVC" reloadable="false" source="org.eclipse.jst.jee.server:SpringMVC">
<Resource name="jdbc/spring"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/springmvc"
username="root"
password="root"
maxActive="100"
maxIdle="30"
maxWait="10000" />
</Context>


上述配置文件中只要注意Resource中name为jndi名称,spring将通过该名称查找数据源。其配置如下:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/spring</value>
</property>
</bean>

创建实体类

           实体类为普通的pojo对象,不再详细描述。本例中包括:Archives.java,Student.java,School.java,Teacher.java,

关系为

student----1------------- 1--------Archives,

School----1---------------n--------Teacher,

Teacher--1---------------n--------Student。

创建Mapper文件

           Mapper文件是实体类和数据库表的映射文件,并且sql语句也在该文件中维护,不是散落在系统中,方便以后的改变。本Demo创建了四个mapper文件分别为:Archives.xml(档案),School.xml(学校),Student.xml(学生),Teacher.xml(教师),将它们放到mapper包下,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ArchivesMapper">
<select id="getArchiveById" resultType="archive">
<![CDATA[
select * from archives where id=#{id}
]]>
</select>

<select id="getAllArchive" resultType="list" resultMap="archiveResultMap">
<![CDATA[
select * from archives
]]>
</select>

<!-- accountMap.accountResultMap是account-resultmap.xml中定义的resultmap,通过namespace.id找到 -->
<select id="getArchiveByNames" parameterType="string" resultMap="archiveResultMap">
<![CDATA[
select * from account where username = #{name}
]]>
</select>

<sql id="user_name_pwd">
username, password
</sql>

<!-- 自动生成id策略 -->
<insert id="addArchive" parameterType="archive">
insert into archives(id, name)
values(#{id}, #{name})
</insert>

<!-- 根据selectKey语句生成主键 -->
<!-- <insert id="addAccount4Key" parameterType="account">
<selectKey keyProperty="account_id" order="BEFORE" resultType="int">
select cast(random() * 10000 as Integer) a from #Tab
</selectKey>
insert into account(account_id, status, username, password)
values(#{accountId}, #{status}, #{username}, #{password})
</insert>
-->

<update id="editAccount" parameterType="archive">
update archives set
name = #{name}
where id = #{id}
</update>

<delete id="removeArchive" parameterType="int">
delete from archives where id = #{id}
</delete>

<resultMap type="entity.Archives" id="archiveResultMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
</resultMap>

</mapper>

其它不再列举,对于其映射原理大家可以参看官网,本文后面会有一个查询举例。

 

 

配置SqlSessionFactory

       在spring配置文件applicationContext.xml中集成MyBatis的配置文件mybatis-config.xml,同时指定数据源,并引入MyBatis的mapper文件,配置如下:

<!-- 创建SqlSessionFactory,同时指定数据源 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations">
<list>
<value>classpath:mapper/*.xml</value>
</list>
</property>
</bean>


配置事务

     本文采用spring的注解方式声明事务,这里需要注意需要开启注解驱动,并且不要重复扫描,否则事务会失效。所谓重复扫描,当开始扫描组件后,应该剔除掉曾经扫描过的注解。如下:

开启注解驱动

<mvc:annotation-driven/>

开启扫描组件,并剔除不需要重复扫描的注解

<context:component-scan>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>

或者指定base-package,如下:

<context:component-scan base-package="service">
</context:component-scan>


指定jdbc事务

<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

此后就可以在代码中通过@Transactional来声明类或者方法使用事务。

Dao层

       使用MyBatis通用dao,SqlSessionDaoSupport其需要引入如下包:mybatis-spring-1.1.1-SNAPSHOT.jar,去其官网下载mybatis-spring-1.2.0-bundle.zip 。自定义一个类CommonDao集成SqlSessionDaoSupport。内容如下:

package dao;

import java.io.Serializable;
import java.util.List;

import javax.annotation.Resource;

import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.stereotype.Repository;

@Repository
public class CommonDao extends SqlSessionDaoSupport {

@Resource(name="sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;

public void save(String key, Object object){
this.getSqlSession().insert(key, object);
}

public void delete(String key, Serializable id){
this.getSqlSession().delete(key, id);
}

public void delete(String key, Object object){
this.getSqlSession().delete(key, object);
}

public <T> T get(String key, Object paramObject){
return this.getSqlSession().selectOne(key, paramObject);
}

public <T> List<T> getList(String key){
return this.getSqlSession().selectList(key);
}

public <T> List<T> getList(String key, Object paramObject){
return this.getSqlSession().selectList(key, paramObject);
}

public <T> List<T> getPageList(String key, Object paramObject, int offset, int limit){
return this.getSqlSession().selectList(key, paramObject,new RowBounds(offset,limit));
}

}

声明了常见的增删改查语句,需要注意的是key为实体mapper文件中的namespace+.+具体的语句id。

Service层

        目前只有一个service,实际开发应该一类业务对应一个service,采用注解的方式托管给spring,其内容如下:

package service;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import dao.CommonDao;

import entity.Archives;
import entity.School;
import entity.Student;
import entity.Teacher;

@Service
public class MenuService {

@Resource(name="commonDao")
private CommonDao commonDao;

public List<Student> find() {

return null;
}

public void delete(int id) {

commonDao.delete("ArchivesMapper.removeArchive", 1);
}

@Transactional
public void savaArchive(Archives archive) {

commonDao.save("ArchivesMapper.addArchive", archive);
}

@Transactional
public void savaStudent(Student student) {

commonDao.save("StudentMapper.addStudent", student);
}

public Student findStu(int id) {

return commonDao.get("StudentMapper.getStudentById", id);
}

/**
* 此方法描述的是:  保存学生信息
* @author: liubo
* @version: 2013-4-7 下午02:26:18
*/

public void saveSchool(School sch) {

commonDao.save("SchoolMapper.addSchool", sch);
}

/**
* 此方法描述的是:根据id查找学校信息
* @author: liubo
* @version: 2013-4-7 下午02:28:05
*/

public School findSch(int id) {

return commonDao.get("SchoolMapper.getSchoolById", id);
}

/**
* 此方法描述的是:保存教师信息
* @author: liubo
* @version: 2013-4-7 下午02:37:32
*/

public void saveTeacher(Teacher tea) {

commonDao.save("TeacherMapper.addTeacher", tea);

}

/**
* 此方法描述的是:根据id查找教师信息
* @author: liubo
* @version: 2013-4-7 下午02:38:21
*/

public Teacher findTea(int id) {
// TODO Auto-generated method stub
return commonDao.get("TeacherMapper.getTeacherById", id);
}

/**
* 此方法描述的是: 分页查找学校信息
* @author: liubo
* @version: 2013-4-8 下午02:14:39
*/

public List<School> findSchList(int offset, int limit) {

return commonDao.getPageList("SchoolMapper.getAllSchool", null, offset, limit);
}

/**
* 此方法描述的是: 分页查找学生信息
* @author: liubo
* @version: 2013-4-8 下午02:38:04
*/

public List<Student> findStuList(int offset, int limit) {

return commonDao.getPageList("StudentMapper.getAllStudent", null, offset, limit);
}

}


控制层

     采用SpringMVC作为控制器,主要针对查询做了测试,内容如下:

/**
*
* @author geloin
* @date 2012-5-5 上午9:31:52
*/
package snippet;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import service.MenuService;

import entity.Archives;
import entity.School;
import entity.Student;
import entity.Teacher;

/**
*
* @author geloin
* @date 2012-5-5 上午9:31:52
*/
@Controller
public class LoginController {
//注入service
@Resource(name="menuService")
private MenuService menuService;

//映射url请求路径
@RequestMapping("/to_login")
public ModelAndView toLogin() throws Exception {

Map<String, Object> map = new HashMap<String, Object>();

//		List<Student> result = this.menuService.find();
//分页查询
List<Student> result = this.menuService.findStuList(0,2);

for(Student stu : result){
System.out.println(stu.getId()+"---"+stu.getArchive());
}

//		System.out.println(menuService);
//		map.put("result", result);
//
//		return new ModelAndView("menu", map);
return null;
}

@RequestMapping("/insert")
public ModelAndView insert() throws Exception {

Archives archive = new Archives();
archive.setName("archive");
try{
menuService.savaArchive(archive);
}catch(Exception e){
e.printStackTrace();
}
return null;
}

@RequestMapping("/insertStu")
public ModelAndView insertStu() throws Exception {
Student stu = new Student();
stu.setName("stu");
Archives archive = new Archives();
archive.setId(1);
stu.setArchive(archive);
try{
menuService.savaStudent(stu);
}catch(Exception e){
e.printStackTrace();
}
return null;
}

@RequestMapping("/selectStu")
public ModelAndView selectStu() throws Exception {
Student stu = menuService.findStu(1);
System.out.print(stu.getArchive().getName());
return null;
}

@RequestMapping("/insertSch")
public ModelAndView insertSch() throws Exception {
School sch = new School();
sch.setName("sch");
try{
menuService.saveSchool(sch);
}catch(Exception e){
e.printStackTrace();
}
return null;
}

@RequestMapping("/selectSch")
public ModelAndView selectSch() throws Exception {
List<School> schList = menuService.findSchList(2,5);
for(School sch : schList){
System.out.println(sch.getId());
System.out.println("--------------------------------");
}
//		List<Teacher> tList = sch.gettList();
return null;
}

@RequestMapping("/insertTea")
public ModelAndView insertTea() throws Exception {
Teacher tea = new Teacher();
tea.setName("tea");
School sch = new School();
sch.setId(1);
tea.setSchool(sch);
try{
menuService.saveTeacher(tea);
}catch(Exception e){
e.printStackTrace();
}
return null;
}

@RequestMapping("/selectTea")
public ModelAndView selectTea() throws Exception {
Teacher tea = menuService.findTea(1);
List<Student> tList = tea.getsList();
return null;
}

}


一对一关联查询

       可以懒加载

一对多关联查询

    可以懒加载

MyBatis缓存

    使用ehcache来做为缓存组件,需要下载mybatis-ehcache-1.0.1-bundle.zip,并将包加入classpath。需要配置文件。

懒加载

    通过配置实现

 

 

以上内容已经测试通过,下次补上。。。

 

 

 

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