`
445822357
  • 浏览: 738706 次
文章分类
社区版块
存档分类
最新评论

阶梯式使用SpringMVC+MyBatis

 
阅读更多

概述

对于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。需要配置文件。

懒加载

通过配置实现

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




分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics