Blog

mysql问题-存储过程之DELIMITER后面要加空格

一、数据库存储过程举例:

1、搭建数据库

id      last_name    gender      email
1	  mike	       0         [email protected]	
2	  book	       0  	[email protected]	
3	  tom	       1        [email protected]	
4	  jerry	       1	[email protected]	
5	  hhee	       1	[email protected]	
6	  jerry4       1	[email protected]	
7	  smith0x1     1	[email protected]	
8	  mas	       1	[email protected]	
9	  smith0x1     1	[email protected]	
10	  allen0x1     0	[email protected]

2、创建存储过程

USE `mybatis`;
DROP PROCEDURE IF EXISTS proc_employee;
DELIMITER //
CREATE PROCEDURE proc_employee(IN p_start INT, IN p_end INT,OUT p_count INT)
BEGIN
  SELECT COUNT(*) INTO p_count FROM `tbl_employee`;
  SELECT * FROM ( SELECT a.*  FROM `tbl_employee` a  WHERE a.`id` < p_end)  b
  WHERE b.`id` >p_start;
END//
DELIMITER ;

特别注意点:

开头部分:DELIMITER //【这两斜杠前面有空格,需要注意】
结尾部分:DELIMITER ;【分号前面也有个空格,需要注意】

在定义过程时,使用DELIMITER // 命令将语句的结束符号从分号 ; 
临时改为//,使得过程体中使用的分号被直接传递到服务器,而不会被客户端(如mysql)解释。

3、mysql客户端调用存储过程

set @p_count=1;
CALL proc_employee(1,8,@p_count); 
select @p_count;

二、数据库操作举例

-- 8-1: Stored Procedure Intro
-- http://www.artfulsoftware.com/mysqlbook/sampler/mysqled1_appe.html
 
-- stored procedures
-- paste this script into the mysql client
 
USE test;
DELIMITER |                      -- // permit semi-colons within SP
 
DROP PROCEDURE IF EXISTS worldmesgproc |
CREATE PROCEDURE worldmesgproc( IN s CHAR( 10 ) )
SELECT CONCAT_WS( ' ', s, 'world!' );
|
 
DROP FUNCTION IF EXISTS worldmesgfunc |
CREATE FUNCTION worldmesgfunc( s CHAR( 10 ) ) RETURNS CHAR( 20 )
RETURN CONCAT_WS( s, 'world!' );
|
 
DELIMITER ;                     -- // restore semi-colon as delimiter
 
CALL worldmesgproc( 'Hello' );
Hello world!
SELECT worldmesgfunc( 'Hello' );
Hello world!
 
CALL worldmesgfunc( 'Hi' );     -- // funcs cannot be called
ERROR 1289 at line 18: PROCEDURE worldmesgfunc does not exist
 
DROP PROCEDURE worldmesgproc;
DROP FUNCTION worldmesgfunc;
 
-- # EOF
 
-- 8-2: DECLARE ... HANDLER in an SP
 
-- # Here,  because DECLARE EXIT HANDLER … instructs MySQL to exit the SP
-- # if  SQLSTATE = 23000, the statement SET @err=-1 never executes. Notice that
-- # in order to be able to mark the end of the SP, the code has to set the delimiter to
-- # something other than a semi-colon; this is best done just before creating the SP,
-- # and reset immediately after. The DELIMITER command does not need a second
-- # terminator.
 
USE test ;
SET @err = 0 ;
SELECT 'Before running errhandlerdemo:', @err ;
CREATE TABLE IF NOT EXISTS testhandler (i INT, PRIMARY KEY(i)) ;
 
DELIMITER |
DROP PROCEDURE IF EXISTS errhandlerdemo ;
CREATE PROCEDURE errhandlerdemo()
  BEGIN
    DECLARE EXIT HANDLER FOR SQLSTATE '23000' SET @err=23000;
    INSERT INTO testhandler VALUES( NULL) ;
    SET @err=-1 ;
  END ;
|
DELIMITER ;
 
CALL errhandlerdemo() |
DROP TABLE testhandler |
SELECT 'After running errhandlerdemo:', @err;
 
-- # EOF
 
-- 8-3:IF...THEN... in an SP
 
USE test;
DROP FUNCTION IF EXISTS is_even;
DELIMITER |
CREATE FUNCTION is_even( x INT ) RETURNS INT
BEGIN
  DECLARE iRet INT DEFAULT 0;
  IF x/2 = 0 THEN
    SET iRet = 1;
  END IF;
  RETURN iRet;
END
|
DELIMITER ;
 
SELECT is_even( 3 );
 
-- #EOF
 
-- 8-4: CASE...WHEN...ENDCASE in an SP
 
USE test;
 
DROP PROCEDURE IF EXISTS case1proc;
DELIMITER |
CREATE PROCEDURE case1proc( IN x INT )
BEGIN
  CASE x
    WHEN 'string' THEN SELECT 'non-matching value will not execute';
    WHEN 0 THEN SELECT 'matching value executes';
    WHEN 17 THEN SELECT 'non-matching value will not execute';
  END CASE;
END;
|
 
DROP PROCEDURE IF EXISTS case2proc |
CREATE PROCEDURE case2proc( IN x INT )
BEGIN
  DECLARE s CHAR( 10 );
  CASE
    WHEN x < 0 THEN SET s = 'less than zero';
    WHEN x < 10 THEN SET s = 'units';
    WHEN x < 100 THEN SET s = 'tens';
    WHEN x < 1000 THEN SET s = 'hundreds';
    ELSE SET s = 'a thousand or more';
  END CASE;
  SELECT CONCAT( 'range is ', s );
END;
|
 
DELIMITER ;
 
CALL case1proc( 0 );           -- # output: matching value executes
CALL case2proc( 100 );         -- # output: range is hundreds
 
-- # EOF
 
-- 8-5: DO .. REPEAT
 
DELIMITER |
 
DROP PROCEDURE IF EXISTS dorepeat;
CREATE PROCEDURE dorepeat( IN imax INT )
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE s CHAR( 20 ) DEFAULT 'Loops:';
REPEAT
BEGIN
SET s = CONCAT_WS( ' ', s, i );
SET i = i + 1;
END;
UNTIL i > imax END REPEAT;
SELECT s;
END
|
 
DELIMITER ;
CALL dorepeat( 5 );
 
-- #EOF
 
-- 8-6: DO ... WHILE ...
 
USE test;
 
DROP PROCEDURE IF EXISTS whileproc;
DELIMITER |
CREATE PROCEDURE whileproc( IN x INT )
BEGIN
   DECLARE i INT DEFAULT 0;
   DECLARE s CHAR( 20 ) DEFAULT "Loops:";
   WHILE i-5 DO
     BEGIN
       SET i = i + 1;
       SET s = CONCAT_WS( ' ', s, i );
     END;
   END WHILE;
   SELECT s;
END;
|
 
DELIMITER ;
 
CALL whileproc( 5 ); -- output: Loops: 1 2 3 4 5
 
-- #EOF
 
-- 8-7: Cursor, handler, loop and iteration in an SP
 
USE test;
DROP TABLE IF EXISTS curtest1;
DROP TABLE IF EXISTS curtest2;
CREATE TABLE curtest1( i INT PRIMARY KEY, j INT, name CHAR(10) );
CREATE TABLE curtest2( x INT );
INSERT INTO curtest1 VALUES (0,0,'first'),(1,2,'second'),(2,1,'third');
 
DROP PROCEDURE IF EXISTS cursxmpl;
DELIMITER |
CREATE PROCEDURE cursxmpl()
BEGIN
  DECLARE mi INT;
  DECLARE mj INT;
  DECLARE done INT DEFAULT 0;
  DECLARE curs CURSOR FOR SELECT i, j FROM test.curtest1;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
 
  OPEN curs;
  loop0: WHILE NOT done DO
    FETCH curs INTO mi, mj;
    IF NOT done THEN
       IF mi < mj THEN
          INSERT INTO test.curtest2 VALUES (mi);
       ELSEIF mi > mj THEN
          INSERT INTO test.curtest2 VALUES (mj);
       ELSE
          ITERATE loop0;
       END IF;
    END IF;
  END WHILE loop0;
  CLOSE curs;
END;
|
DELIMITER ;
CALL cursxmpl();
SELECT * FROM curtest2;
 
-- # EOF

 

mybatis扩展-存储过程

一、存储过程调用关键

1、SQL映射文件中,使用select标签定义调用存储过程
(1)statementType=”CALLABLE”:表示要调用存储过程
(2){call procedure_name(params)}
2、编辑存储过程对象,用于保存存储过程的输入参数和输出参数

二、存储过程调用-mysql

1、搭建数据库

id      last_name    gender      email
1	  mike	       0         [email protected]	
2	  book	       0  	[email protected]	
3	  tom	       1        [email protected]	
4	  jerry	       1	[email protected]	
5	  hhee	       1	[email protected]	
6	  jerry4       1	[email protected]	
7	  smith0x1     1	[email protected]	
8	  mas	       1	[email protected]	
9	  smith0x1     1	[email protected]	
10	  allen0x1     0	[email protected]

2、创建存储过程

USE `mybatis`;
DROP PROCEDURE IF EXISTS proc_employee;
DELIMITER //
CREATE PROCEDURE proc_employee(IN p_start INT, IN p_end INT,OUT p_count INT)
BEGIN
  SELECT COUNT(*) INTO p_count FROM `tbl_employee`;
  SELECT * FROM ( SELECT a.*  FROM `tbl_employee` a  WHERE a.`id` < p_end)  b
  WHERE b.`id` >p_start;
END//
DELIMITER ;

特别注意点:

开头部分:DELIMITER //【这两斜杠前面有空格,需要注意】
结尾部分:DELIMITER ;【分号前面也有个空格,需要注意】

在定义过程时,使用DELIMITER // 命令将语句的结束符号从分号 ; 
临时改为//,使得过程体中使用的分号被直接传递到服务器,而不会被客户端(如mysql)解释。

3、mysql客户端测试端调用存储过程

set @p_count=1;
CALL proc_employee(1,8,@p_count); 
select @p_count;

4、编辑全局配置文件

<?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>


	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
				<property name="username" value="root" />
				<property name="password" value="Cool123!" />
			</dataSource>
		</environment>
	</environments>
	
		<!-- 5、databaseIdProvider:支持多数据库厂商的;
		 type="DB_VENDOR":VendorDatabaseIdProvider
		 	作用就是得到数据库厂商的标识(驱动getDatabaseProductName()),mybatis就能根据数据库厂商标识来执行不同的sql;
		 	MySQL,Oracle,SQL Server,xxxx
	  -->
	<databaseIdProvider type="DB_VENDOR">
		<!-- 为不同的数据库厂商起别名 -->
		<property name="MySQL" value="mysql"/>
		<property name="Oracle" value="oracle"/>
		<property name="SQL Server" value="sqlserver"/>
	</databaseIdProvider>
	
	<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 
	如果 数据库全局文件 和 子配置文件 不在同一个目录 ,就需要 /目录/目录/.../EmployeeMapper_old.xml
	-->
	<mappers>
	    <!-- 新方法操作mybatis 需要 的配置文件 -->
		<mapper resource="EmployeeMapper.xml" />
	</mappers>
</configuration>

5、编辑javabean

Employee.java

package com.mybatis.bean;

public class Employee {
	private Integer id;
	private String lastName;
	private String email;
	private String gender;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}
	
	public Employee(){
		super();
	}
	
	public Employee(String lastName, String email, String gender) {
		super();
		this.lastName = lastName;
		this.email = email;
		this.gender = gender;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";
	}

}

存储过程的bean文件  ProcPage.java

package com.mybatis.bean;

import java.util.List;

/**
 * 封装分页查询数据
 * @author lfy
 *
 */
public class ProcPage {
	
	private int start;
	private int end;
	private int count;
	private List<Employee> emps;
	
	public int getStart() {
		return start;
	}
	public void setStart(int start) {
		this.start = start;
	}
	public int getEnd() {
		return end;
	}
	public void setEnd(int end) {
		this.end = end;
	}
	public int getCount() {
		return count;
	}
	public void setCount(int count) {
		this.count = count;
	}
	public List<Employee> getEmps() {
		return emps;
	}
	public void setEmps(List<Employee> emps) {
		this.emps = emps;
	}
	
	

}

6、配置mapper接口

EmployeeMapper.java

package com.mybatis.mapper;

import java.util.List;

import com.mybatis.bean.Employee;
import com.mybatis.bean.ProcPage;

public interface EmployeeMapper {
	
	public List<Employee> getPageByProcedure(ProcPage page);
	
}

7、配置SQL映射文件

EmployeeMapper.xml

<?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="com.mybatis.mapper.EmployeeMapper">
	

	 <!-- public void getPageByProcedure(); 
	1、使用select标签定义调用存储过程
	2、statementType="CALLABLE":表示要调用存储过程
	3、{call procedure_name(params)}
	-->
	<select id="getPageByProcedure" statementType="CALLABLE" databaseId="mysql" resultMap="PageEmp">
		{
		call proc_employee(
			#{start,mode=IN,jdbcType=INTEGER},
			#{end,mode=IN,jdbcType=INTEGER},
			#{count,mode=OUT,jdbcType=INTEGER}
		)
		}
	</select>
	<resultMap type="com.mybatis.bean.Employee" id="PageEmp">
		<id column="ID" property="id"/>
		<result column="LAST_NAME" property="lastName"/>
		<result column="EMAIL" property="email"/>
	</resultMap>
	 
	
</mapper>

8、Junit单元测试

package com.mybatis.test;


import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.mybatis.bean.ProcPage;
import com.mybatis.mapper.EmployeeMapper;


/**
 * 1、接口式编程
 * 	原生:		Dao		====>  DaoImpl
 * 	mybatis:	Mapper	====>  xxMapper.xml
 * 
 * 2、SqlSession代表和数据库的一次会话;用完必须关闭;
 * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。(就是不要放在共享成员变量里面,A线程用完释放,B线程再用就为空了)
 * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
 * 		(将接口和xml进行绑定)
 * 		EmployeeMapper empMapper =	sqlSession.getMapper(EmployeeMapper.class);
 * 5、两个重要的配置文件:
 * 		mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
 * 		sql映射文件:保存了每一个sql语句的映射信息:
 * 					将sql抽取出来。	
 *
 */

public class MybatisTest {
	
	public SqlSessionFactory getSqlSessionFactory() throws IOException {
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		return new SqlSessionFactoryBuilder().build(inputStream);
	}
	
	/**
	 * mysql分页:
	 * 存储过程包装分页逻辑
	 * @throws IOException 
	 */
	@Test
	public void testProcedure() throws IOException{
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try{
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			ProcPage page = new ProcPage();
			page.setStart(5);
			page.setEnd(8);
			page.setEmps(mapper.getPageByProcedure(page));
			
			System.out.println("总记录数:"+page.getCount());
			System.out.println("查出的数据:"+page.getEmps().size());
			System.out.println("查出的数据:"+page.getEmps());
		}finally{
			openSession.close();
		}
		
	}
}

三、存储过程调用流程-oracle

基本和mysql相同,部分不相同。【因为存储过程不一样,存储过程对应有四个参数,导致后面的操作稍微不同】

1、数据库存储过程:

create or replace procedure
proc_employee(p_start in int,
              p_end in int,
              p_count out int,
              ref_cur out sys_refcursor) AS
BEGIN 
   select count(*) into p_count from tbl_employee;
   open ref_cur for
        select * from (select e.*,rownum as rn) from tbl_employee e where rownum <p_end)
        where rn >p_start;
END proc_employee;

2、mapper接口文件

package com.mybatis.mapper;

import java.util.List;

import com.mybatis.bean.Employee;
import com.mybatis.bean.ProcPage;

public interface EmployeeMapper {
	
	public void getPageByProcedure(ProcPage page);
	
}

3、SQL映射文件

<mapper namespace="com.mybatis.mapper.EmployeeMapper">

	<!-- public void getPageByProcedure(); 
	1、使用select标签定义调用存储过程
	2、statementType="CALLABLE":表示要调用存储过程
	3、{call procedure_name(params)}
	-->
	
	<select id="getPageByProcedure" statementType="CALLABLE" databaseId="oracle">
		{call hello_test(
			#{start,mode=IN,jdbcType=INTEGER},
			#{end,mode=IN,jdbcType=INTEGER},
			#{count,mode=OUT,jdbcType=INTEGER},
			#{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=PageEmp}
		)}
	</select>
	<resultMap type="com.mybatis.bean.Employee" id="PageEmp">
		<id column="EMPLOYEE_ID" property="id"/>
		<result column="LAST_NAME" property="email"/>
		<result column="EMAIL" property="email"/>
	</resultMap>
	
</mapper>

4、Junit单元测试

/**
 * oracle分页:
 * 		借助rownum:行号;子查询;
 * 存储过程包装分页逻辑
 * @throws IOException 
 */
@Test
public void testProcedure() throws IOException{
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try{
		EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
		OraclePage page = new OraclePage();
		page.setStart(1);
		page.setEnd(5);
		mapper.getPageByProcedure(page);
			
		System.out.println("总记录数:"+page.getCount());
		System.out.println("查出的数据:"+page.getEmps().size());
		System.out.println("查出的数据:"+page.getEmps());
	}finally{
		openSession.close();
	}
		
}

 

mybatis扩展-批量操作

批量操作的关键,就是 opensession 中的 带有 ExecutorType.BATCH,除此之外,和一般的操作没有区别。

一、mybatis独立环境中

@Test
public void testBatch() throws IOException{
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		
	//可以执行批量操作的sqlSession
	SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
	long start = System.currentTimeMillis();
	try{
		EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
		for (int i = 0; i < 10000; i++) {
			mapper.addEmp(new Employee(UUID.randomUUID().toString().substring(0, 5), "b", "1"));
		}
		openSession.commit();
		long end = System.currentTimeMillis();
		//批量:(预编译sql一次==>设置参数===>10000次===>执行(1次))
		//Parameters: 616c1(String), b(String), 1(String)==>4598
		//非批量:(预编译sql=设置参数=执行)==》10000    10200
		System.out.println("执行时长:"+(end-start));
	}finally{
		openSession.close();
	}
		
}

上面的代码如果是:下面这样的,那么sqlsession 就是非批量的,执行速度就慢了。

SqlSession openSession = sqlSessionFactory.openSession();

二、mybatis与spring整合【即SSM框架】环境

需要在spring-ioc容器配置文件(一般取名叫: applicationContext.xml)中添加带有ExecutorType.BATCH的 sqlSession对象。

<!--配置一个可以进行批量执行的sqlSession  -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
	<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg>
	<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>

然后就可以在service中,自动注入 sqlSession

举例:EmployeeService.java

package com.test.springmvc.service;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.test.springmvc.bean.Employee;
import com.test.springmvc.dao.EmployeeMapper;

@Service
public class EmployeeService {
	
	//employeeMapper 是靠 applicationContext.xml的IOC容器,自动创建并赋值到这里的。
	@Autowired
	private EmployeeMapper employeeMapper;

    public List<Employee> getEmps(){
		
		return employeeMapper.getEmps();
	}
	
	//sqlSession 是为了从 applicationContext.xml的IOC容器中 获取批量处理的 sqlSession 对象,并赋值给自己
	@Autowired
	private SqlSession sqlSession;
	
	public List<Employee> getEmpsBatch(){
		EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);		
		return mapper.getEmps();
	}
	
	
}

这样 控制器 controller 的写法可以写成这样了:

package com.test.springmvc.controller;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.test.springmvc.bean.Employee;
import com.test.springmvc.service.EmployeeService;

@Controller
public class EmployeeController {
	
	@Autowired
	EmployeeService employeeService;
	
	@RequestMapping("/getemps")
	public String emps(Map<String,Object> map){

                //没有采用批量处理的方法
                //List<Employee> emps = employeeService.getEmps();
		
                //采用批量处理的方法
                List<Employee> emps = employeeService.getEmpsBatch();
		map.put("allEmps", emps);
		return "list";
	}

}

 

mybatis插件-原理及开发

一、插件原理

1、MyBatis在四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。

2、MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。

3、默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
•Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
•ParameterHandler(getParameterObject, setParameters)
•ResultSetHandler(handleResultSets, handleOutputParameters)
•StatementHandler(prepare, parameterize, batch, update, query)

/**
 * 插件原理
 * 在四大对象创建的时候
 * 1、每个创建出来的对象不是直接返回的,而是
 *  xxx = interceptorChain.pluginAll(parameterHandler);
    
   具体方法如下:其实就是遍历调用了每个插件的plugin(target)方法,
      如果插件的方法签名和目标对象一致,就返回目标对象的代理对象,否则就返回目标对象
	public Object pluginAll(Object target) {
	    for (Interceptor interceptor : interceptors) {
	      target = interceptor.plugin(target);
	    }
	    return target;
	  }
      

 * 2、获取到所有的Interceptor(拦截器)(插件需要实现的接口);
 * 		调用interceptor.plugin(target);返回target包装后的对象
 * 3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面)
 * 		我们的插件可以为四大对象创建出代理对象;
 * 		代理对象就可以拦截到四大对象的每一个执行;
 * 		
 */

接口方法:
•Intercept:拦截目标方法执行
•plugin:生成动态代理对象,可以使用MyBatis提供的Plugin类的wrap方法
•setProperties:注入插件配置时设置的属性

二、插件编写过程

1、编写Interceptor的实现类

package com.mybatis.plugin;

import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

/**
 * 完成插件签名:
 *	      告诉MyBatis当前插件用来拦截哪个对象的哪个方法
 */
@Intercepts(
		{
			@Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
		})
public class MyFirstPlugin implements Interceptor{

	/**
	 * intercept:拦截:
	 * 		拦截目标对象的目标方法的执行;
	 */
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("MyFirstPlugin...intercept:"+invocation.getMethod());
		//动态的改变一下sql运行的参数:以前1号员工,实际从数据库查询3号员工
		Object target = invocation.getTarget();
		System.out.println("当前拦截到的对象:"+target);
		//拿到:StatementHandler==>ParameterHandler===>parameterObject
		//拿到target的元数据
		MetaObject metaObject = SystemMetaObject.forObject(target);
		Object value = metaObject.getValue("parameterHandler.parameterObject");
		System.out.println("sql语句用的参数是:"+value);
		//修改完sql语句要用的参数
		metaObject.setValue("parameterHandler.parameterObject", 11);
		//执行目标方法
		Object proceed = invocation.proceed();
		//返回执行后的返回值
		return proceed;
	}

	/**
	 * plugin:
	 * 	包装目标对象的:包装:为目标对象创建一个代理对象
	 */
	@Override
	public Object plugin(Object target) {
		// TODO Auto-generated method stub
		//我们可以借助Plugin的wrap方法来使用当前Interceptor包装我们目标对象
		System.out.println("MyFirstPlugin...plugin:mybatis将要包装的对象"+target);
		Object wrap = Plugin.wrap(target, this);
		//返回为当前target创建的动态代理
		return wrap;
	}

	/**
	 * setProperties:
	 * 		将插件注册时 的property属性设置进来
	 */
	@Override
	public void setProperties(Properties properties) {
		// TODO Auto-generated method stub
		System.out.println("插件配置的信息:"+properties);
	}

}

 2、使用@Intercepts注解完成插件签名

已经在前面的MyFirstPlugin.java添加了,注解签名。

@Intercepts(
{
	@Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
})

3、将写好的插件注册到全局配置文件中

在mybatis-config.xml中,添加插件配置项:

<!--plugins:注册插件  -->
<plugins>
	<plugin interceptor="com.atguigu.mybatis.dao.MyFirstPlugin">
		<property name="username" value="root"/>
		<property name="password" value="123456"/>
	</plugin>
	<plugin interceptor="com.atguigu.mybatis.dao.MySecondPlugin"></plugin>
</plugins>

三、多插件加载顺序

会根据mybatis的配置的插件顺序依次加载。
一个目标对象如果有多个插件,会在目标的代理对象上继续创建代理。

mybatis运行原理

一、基本介绍

/**
 * 1、获取sqlSessionFactory对象:
 * 		解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession;
 * 		注意:【MappedStatement】:代表一个增删改查的详细信息
 * 
 * 2、获取sqlSession对象
 * 		返回一个DefaultSQlSession对象,包含Executor和Configuration;
 * 		这一步会创建Executor对象;
 * 
 * 3、获取接口的代理对象(MapperProxy)
 * 		getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象
 * 		代理对象里面包含了,DefaultSqlSession(Executor)
 * 4、执行增删改查方法
 * 
 * 总结:
 * 	1、根据配置文件(全局,sql映射)初始化出Configuration对象
 * 	2、创建一个DefaultSqlSession对象,
 * 		他里面包含Configuration以及
 * 		Executor(根据全局配置文件中的defaultExecutorType创建出对应的Executor)
 *  3、DefaultSqlSession.getMapper():拿到Mapper接口对应的MapperProxy;
 *  4、MapperProxy里面有(DefaultSqlSession);
 *  5、执行增删改查方法:
 *  		1)、调用DefaultSqlSession的增删改查(Executor);
 *  		2)、会创建一个StatementHandler对象。
 *  			(同时也会创建出ParameterHandler和ResultSetHandler)
 *  		3)、调用StatementHandler预编译参数以及设置参数值;
 *  			使用ParameterHandler来给sql设置参数
 *  		4)、调用StatementHandler的增删改查方法;
 *  		5)、ResultSetHandler封装结果
 *  注意:
 *  	四大对象每个创建的时候都有一个interceptorChain.pluginAll(parameterHandler);
 *

二、运行流程图

 

mybatis自生成-(2)-简单使用与复杂使用

在MBG.xml 配置文件中,有 多种  targetRuntime 可以设置。

<!--

targetRuntime="MyBatis3Simple":生成简单版的CRUD

MyBatis3:豪华版

-->
1、当用simple 方式 生成代码时,可以用下面的代码测试效果。
@Test
public void testMyBatis3Simple() throws IOException{
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try{
		EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
		List<Employee> list = mapper.selectByExample(null);
		for (Employee employee : list) {
			System.out.println(employee.getId());
		}
	}finally{
		openSession.close();
	}
}
2、当用 MyBatis3 方式时,可以用下面代码测试:
@Test
public void testMyBatis3() throws IOException{
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try{
		EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
		//xxxExample就是封装查询条件的
		//1、查询所有
		//List<Employee> emps = mapper.selectByExample(null);
		//2、查询员工名字中有e字母的,和员工性别是1的
		//封装员工查询条件的example
		EmployeeExample example = new EmployeeExample();
		//创建一个Criteria,这个Criteria就是拼装查询条件
		//select id, last_name, email, gender, d_id from tbl_employee 
		//WHERE ( last_name like ? and gender = ? ) or email like "%e%"
		Criteria criteria = example.createCriteria();
		criteria.andLastNameLike("%e%");
		criteria.andGenderEqualTo("1");
			
		Criteria criteria2 = example.createCriteria();
		criteria2.andEmailLike("%e%");
		example.or(criteria2);
			
		List<Employee> list = mapper.selectByExample(example);
		for (Employee employee : list) {
			System.out.println(employee.getId());
		}
			
	}finally{
		openSession.close();
	}
}

 

 

mybatis自生成-(1)-配置MBG

一、MyBatis Generator (MBG) 简介

Mybatis Generator是MyBatis和ibatis的代码生成器。主要生成如下:
(1)与表结构匹配的Java POJO(字段名对应属性)【javabean类】
(2)SQL映射XML文件(文件为配置中每个表上的简单CRUD(增删改查)函数生成SQL。)【beanMapper.xml】
(3)符合Spring框架的DAO接口java类【beanMapper.java】


二、配置MBG

1、搭建数据库

tbl_employee表【d_id 是外键 对应 tbl_dept表】

id	last_name    gender	  email       d_id
1	   mike	       0      [email protected]      1
2          book        0      [email protected]    2
3          tom         1      [email protected]    2
4          jerry       1       [email protected]       1

tbl_dept表:

id    dept_name
1      开发部
2      测试部

2、项目需要jar包:

总共需要导入项目的jar包就三个

mybatis.jar
mybatis-generator-core.jar
mysql-connector.jar

3、自动生成代码的配置文件

mbg.xml 【需要放在项目根目录,因为执行代码需要读取匹配配置文件路径】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>

	<!-- 
		targetRuntime="MyBatis3Simple":生成简单版的CRUD
		MyBatis3:豪华版	
	 -->
  
  <context id="testTables" targetRuntime="MyBatis3">
		<commentGenerator>
			<!-- 是否去除自动生成的注释 true:是 : false:否 -->
			<property name="suppressAllComments" value="true" />
		</commentGenerator>
		<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
  	    <!-- jdbcConnection:指定如何连接到目标数据库 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
           connectionURL="jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true"
           userId="root"
           password="Cool123!">
        </jdbcConnection>
	

		<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
			NUMERIC 类型解析为java.math.BigDecimal -->
		<javaTypeResolver>
			<property name="forceBigDecimals" value="false" />
		</javaTypeResolver>

		<!-- targetProject:生成PO类的位置 -->
		<javaModelGenerator targetPackage="com.mybatis.bean"
			targetProject="./src">
			<!-- enableSubPackages:是否让schema作为包的后缀 -->
			<property name="enableSubPackages" value="false" />
			<!-- 从数据库返回的值被清理前后的空格 -->
			<property name="trimStrings" value="true" />
		</javaModelGenerator>
		
		<!-- targetProject:mapper映射文件生成的位置 -->
		<sqlMapGenerator targetPackage="com.mybatis.mapper"
			targetProject="./conf">
			<!-- enableSubPackages:是否让schema作为包的后缀 -->
			<property name="enableSubPackages" value="false" />
		</sqlMapGenerator>
		
		<!-- targetPackage:mapper接口生成的位置 -->
		<javaClientGenerator type="XMLMAPPER"
			targetPackage="com.mybatis.mapper"
			targetProject="./src">
			<!-- enableSubPackages:是否让schema作为包的后缀 -->
			<property name="enableSubPackages" value="false" />
		</javaClientGenerator>
		
		
		<!-- 指定要逆向分析哪些表:根据表要创建javaBean -->
        <table tableName="tbl_dept" domainObjectName="Department"></table>
        <table tableName="tbl_employee" domainObjectName="Employee"></table>
		
	
	</context>
  
  
</generatorConfiguration>

注意:mbg配置文件中,对各标签有顺序要求。先javaModelGenerator  后 
sqlMapGenerator最后  javaClientGenerator

4、执行代码自动生成文件

新建包 com.mybatis.test,并在下面创建 Junit 测试类  MybatisTest.java

package com.mybatis.test;

import java.io.File;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;


public class MybatisTest {

	
	@Test
	public void testMbg() throws Exception {
		List<String> warnings = new ArrayList<String>();
		boolean overwrite = true;
		File configFile = new File("mbg.xml");// mbg.xml为上面创建的配置文件。
		ConfigurationParser cp = new ConfigurationParser(warnings);
		Configuration config = cp.parseConfiguration(configFile);
		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
		myBatisGenerator.generate(null);

	}

}
生成代码遇到的问题:
1、mbg.xml 必须 放在项目根目录,不能放在 src目录下或者其他目录下。
//因为在自动 生成代码过程中,需要读取 mbg.xml 配置文件,路径需要匹配
File configFile = new File("mbg.xml");// mbg.xml为上面创建的配置文件。
2、报错找不到 : java.time 类,因为这个是java8 的,当前是jdk7代码环境。
java.lang.NoClassDefFoundError: java/time/temporal/TemporalAccessor
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:278)
at org.mybatis.generator.internal.ObjectFactory.internalClassForName(ObjectFactory.java:142)
at org.mybatis.generator.internal.ObjectFactory.createInternalObject(ObjectFactory.java:178)
3、Mybatis Generator代码不报错,但是没有生成文件

比如:之前是 targetProject=”.\src”  适用于windows,在当前目录的src创建文件。
targetProject=”./src”  适用于 linux ,在当前目录的 src 创建文件。
【Windows 无法识别  ./     同理 linux 也无法识别  .\】

<javaClientGenerator type="XMLMAPPER"
	targetPackage="com.mybatis.mapper"
	targetProject=".\src">
	<!-- enableSubPackages:是否让schema作为包的后缀 -->
	<property name="enableSubPackages" value="false" />
</javaClientGenerator>

MBG 配置目录的时候 targetProject=“./src”  需要知道 是windows环境还是mac环境。主要是 目录设置问题。windows环境:.\    mac环境:./ 

当然目录可以去掉前面./或.\  直接开始写文件夹就行了,这样子 mac和windows都可以运行了。

 

java工具-log4j框架-自动加载原理

log4j,如何“自动加载”?

今天看代码,发现log4j.properties。没有相应的加载代码,但它却生效了,这多神奇!
看进去,org.apache.log4j, LogManager.java,其有一个static方法块:

static {
    // By default we use a DefaultRepositorySelector which always returns 'h'.
    Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    repositorySelector = new DefaultRepositorySelector(h);

    /** Search for the properties file log4j.properties in the CLASSPATH.  */
    String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
                               null);

    // if there is no default init override, then get the resource
    // specified by the user or the default config file.
    if(override == null || "false".equalsIgnoreCase(override)) {

      String configurationOptionStr = OptionConverter.getSystemProperty(
                              DEFAULT_CONFIGURATION_KEY, 
                              null);

      String configuratorClassName = OptionConverter.getSystemProperty(
                                                   CONFIGURATOR_CLASS_KEY, 
                           null);

      URL url = null;

      // if the user has not specified the log4j.configuration
      // property, we search first for the file "log4j.xml" and then
      // "log4j.properties"
      if(configurationOptionStr == null) {    
    url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
    if(url == null) {
      url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
    }
      } else {
    try {
      url = new URL(configurationOptionStr);
    } catch (MalformedURLException ex) {
      // so, resource is not a URL:
      // attempt to get the resource from the class path
      url = Loader.getResource(configurationOptionStr); 
    }    
      }
      
      // If we have a non-null url, then delegate the rest of the
      // configuration to the OptionConverter.selectAndConfigure
      // method.
      if(url != null) {
    LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");      
    OptionConverter.selectAndConfigure(url, configuratorClassName, 
                       LogManager.getLoggerRepository());
      } else {
    LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
      }
    }  
  }

换句话说,是什么呢?也就是说:

1. 获取系统属性,看是否用户设置了override。默认是不设置的。
2. 如果确实没有设置,那么尝试找一下,有没有log4j.xml,有则加载。
3. 如果还没有,那么尝试找一下,有没有log4j.properites,有则加载。

其中,2、3里提到的“尝试找一下”,可能是去哪个目录里面找呢?翻译了一下,效果不好,还是上原文清晰 :

Search for resource using the thread context class loader under Java2. If that fails, search for resource using the class loader that loaded this class (Loader). Under JDK 1.1, only the the class loader that loaded this class (Loader) is used.
Try one last time with ClassLoader.getSystemResource(resource), that is is using the system class loader in JDK 1.2 and virtual machine’s built-in class loader in JDK 1.1.

所以,你把log4j.xml或log4j.properties放在这些目录下,那么log4j会“自动去加载”到,不用程序里手工写加载代码了。

但我个人,还是倾向于自己写加载。因为这种“悄悄被人做掉”,一是代码很难理解,二是假如A同学放了一个log4j,B同学又写了一个放在其他目录,这种默认加载机制,不一定哪个生效及生效顺序。这种不确定性,还是自己写两行代码,消灭在摇篮里吧。

来自:http://www.cnblogs.com/alipayhutu/archive/2013/04/18/3028249.html

mybatis框架整合-SSM简单入门详解

为了方便复习,总结了SSM框架的搭建过程:
用的是eclipse 和tomcat服务器。创建了一个 Dynamic web project。
有关这些基础相关资料,可以查找网络。

一、项目整合概览

 

二、项目jar包介绍

jar包下载地址:http://central.maven.org/maven2/org/springframework/

其实,source.jar 是用来查看源代码的,javadoc.jar 是用来查看 文档的。这些可以去掉。

1、Spring IOC jar包:

core , content , bean , 在启动服务器 时需要 common log,在加载 容器时 需要 expression(spring 的标签语言),aop模块(面向切面编程)

2、SpringMVC jar包

只要 spring-webmvc.jar 包就行了。如果整合 struts框架,那么spring-webmvc.jar这个就不用了,spring 整合 Struts时 用 Struts 提供的整合 插件

3、jsp页面用jstl标签语言

当在jsp页面使用 jstl标签语言时,需要导入 jstl.jar 包。
比如 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

4、数据库问题

mybatis核心包【mybatis.jar 】
mybatis 与spring整合包【mybatis-spring.jar】

mysql数据库驱动包 【mysql-connector.jar】

数据库 解析注解事务 【spring-tx.jar】

<!-- spring IOC 容器配置文件中, 开启基于注解的事务 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

数据源包:根据不同数据源 配置,导入不同包

下面就是 导入 spring-jdbc.jar

<!-- spring IOC 容器配置文件中, 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="com.mysql.jdbc.Driver" />
	<!-- http://jingyan.baidu.com/article/b7001fe197a3f60e7282dd8d.html 中文数据库存取乱码问题 -->
	<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8" />
	<property name="username" value="root" />
	<property name="password" value="Cool123!" />
</bean>

当然数据库配置文件,可以写在properties文件中,然后用${}引用。比如下面
当然这里的数据源也修改了:所以要用 c3p0.jar 包。

<!-- 引入数据库的配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties" />
<!-- Spring IOC 容器配置文件中,用来控制数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="jdbcUrl" value="${jdbc.url}"></property>
	<property name="driverClass" value="${jdbc.driver}"></property>
	<property name="user" value="${jdbc.username}"></property>
	<property name="password" value="${jdbc.password}"></property>
</bean>

关于数据源的写法,也可以有另一种写法:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName">
		<value>com.mysql.jdbc.Driver</value>
	</property>
	<property name="url">
		<value>jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8
		</value>
	</property>
	<property name="username">
		<value>root</value>
	</property>
	<property name="password">
		<value>Cool123!</value>
	</property>
</bean>

三、数据库搭建

简单举例:

id	last_name    gender	  email      
1	   mike	       0      [email protected]     
2          book        0      [email protected]   
3          tom         1      [email protected]   
4          jerry       1       [email protected]       

四、SSM项目搭建

1、编辑web.xml

文件中添加了:
1、spring-mvc 配置文件【springmvc-servlet.xml】
2、spring-ioc 配置文件【applicationContext.xml】

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>Mybatis_06_SSM</display-name>
 
 
   <!--Spring配置: needed for ContextLoaderListener -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>

	<!-- Bootstraps the root web application context before servlet initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!-- SpringMVC配置 -->
	<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
 

  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
</web-app>

2、配置springmvc-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!--SpringMVC只是控制网站跳转逻辑  -->
	<!-- 只扫描控制器 -->
	<context:component-scan base-package="com.test.springmvc" use-default-filters="false">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<!-- 视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	
	<mvc:annotation-driven></mvc:annotation-driven>
	<mvc:default-servlet-handler/>
</beans>

3、编辑请求页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="getemps">查询所有员工</a>
</body>
</html>

4、编辑控制器controller层

package com.test.springmvc.controller;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.test.springmvc.bean.Employee;
import com.test.springmvc.service.EmployeeService;

@Controller
public class EmployeeController {
	
	@Autowired
	EmployeeService employeeService;
	
	@RequestMapping("/getemps")
	public String emps(Map<String,Object> map){
		List<Employee> emps = employeeService.getEmps();
		map.put("allEmps", emps);
		return "list";
	}

}

5、编辑bean层和显示结果页

Employee.java

package com.test.springmvc.bean;


public class Employee {
	
	
	private Integer id;
	private String lastName;
	private String email;
	private String gender;
	
	public Employee() {
		super();
	}
	

	public Employee(Integer id, String lastName, String email, String gender) {
		super();
		this.id = id;
		this.lastName = lastName;
		this.email = email;
		this.gender = gender;
	}
	

	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	
	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email="
				+ email + ", gender=" + gender + "]";
	}
	
}

list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>员工列表</title>
</head>
<body>
	<table>
			<tr>
				<td>id</td>
				<td>lastName</td>
				<td>email</td>
				<td>gender</td>
			</tr>
		<c:forEach items="${allEmps }" var="emp">
			<tr>
				<td>${emp.id }</td>
				<td>${emp.lastName }</td>
				<td>${emp.email }</td>
				<td>${emp.gender }</td>
			</tr>
		</c:forEach>
	
	</table>

</body>
</html>

6、编辑Service层和Dao层

EmployeeService.java

package com.test.springmvc.service;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.test.springmvc.bean.Employee;
import com.test.springmvc.dao.EmployeeMapper;

@Service
public class EmployeeService {
	
	@Autowired
	private EmployeeMapper employeeMapper;
	
	@Autowired
	private SqlSession sqlSession;
	
	public List<Employee> getEmps(){
		
		return employeeMapper.getEmps();
	}

}

EmployeeMapper.java

package com.test.springmvc.dao;


import java.util.List;

import com.test.springmvc.bean.Employee;


public interface EmployeeMapper {
	
	public Employee getEmpById(Integer id);
	
	public List<Employee> getEmps();
	

}

7、编辑applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!-- Spring希望管理所有的业务逻辑组件,等。。。 -->
	<context:component-scan base-package="com.test.springmvc">
		<context:exclude-filter type="annotation"
			expression="org.springframework.stereotype.Controller" />
	</context:component-scan>

<!-- 引入数据库的配置文件 -->
<!-- 	
	<context:property-placeholder location="classpath:dbconfig.properties" />
	Spring用来控制业务逻辑。数据源、事务控制、aop
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean> -->
	
	
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<!-- http://jingyan.baidu.com/article/b7001fe197a3f60e7282dd8d.html 中文数据库存取乱码问题 -->
		<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8" />
		<property name="username" value="root" />
		<property name="password" value="Kitty521!" />
	</bean>
	
	<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName">
			<value>com.mysql.jdbc.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8
			</value>
		</property>
		<property name="username">
			<value>root</value>
		</property>
		<property name="password">
			<value>Kitty521!</value>
		</property>
	</bean> -->
	
	
	<!-- spring事务管理 -->
	<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 开启基于注解的事务 -->
	<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
	
	<!-- 
	整合mybatis 
		目的:1、spring管理所有组件。mapper的实现类。
				service==>Dao   @Autowired:自动注入mapper;
			2、spring用来管理事务,spring声明式事务
	-->
	<!--创建出SqlSessionFactory对象  -->
	<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<!-- configLocation指定全局配置文件的位置 -->
		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
		<!--mapperLocations: 指定mapper文件的位置-->
		<property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property>
	</bean>
	
	
	<!-- 扫描所有的mapper接口的实现,让这些mapper能够自动注入;
	base-package:指定mapper接口的包名
	 -->
	<mybatis-spring:scan base-package="com.test.springmvc.dao"/>
	<!-- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.test.springmvc.dao"></property>
	</bean> -->
	
</beans>

8、数据库配置文件和mybatis全局配置文件

dbconfig.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true
jdbc.username=root
jdbc.password=Cool123!

orcl.driver=oracle.jdbc.OracleDriver
orcl.url=jdbc:oracle:thin:@localhost:1521:orcl
orcl.username=scott
orcl.password=123456

mybatis-config.xml

<?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>
	
    <!--显式的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
	<settings>
		
		<!-- 开启数据库字段 自动 驼峰大小写转换,比如数据库 last_name 字段 会自动转换 赋值给bean中 的 lastName 属性-->
		<setting name="mapUnderscoreToCamelCase" value="true"/>
		
		<!-- 主要是因为 插入 null 到 oracle会报错,因为插入类型是JdbcType OTHER ,所以这里设置类型 为 NULL  来解决oracle 插入null报错问题-->
		<setting name="jdbcTypeForNull" value="NULL"/>
		
		<!-- 下面两个设置,是为了开启 mybatis的 延迟加载功能 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
		
	</settings>
	
	<!-- 给数据库类型取别名,方便SQL映射文件,可以根据不同类型数据库,来写相应SQL语句 -->
	<databaseIdProvider type="DB_VENDOR">
		<property name="MySQL" value="mysql"/>
		<property name="Oracle" value="oracle"/>
		<property name="SQL Server" value="sqlserver"/>
	</databaseIdProvider>
	
<!-- 已经在 spring ioc 容器中 配置了 sql 映射文件了,这里就不需要了写了,两个地方只要 有一个地方写了SQL映射文件就行
    <mappers>
	<mapper resource="mybatis/mapper/EmployeeMapper.xml" />
	</mappers> -->
	
</configuration>

9、mybatis之SQL映射文件

EmployeeMapper.xml

<?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="com.test.springmvc.dao.EmployeeMapper">

	<!-- public Employee getEmpById(Integer id); -->
	<select id="getEmpById" resultType="com.test.springmvc.bean.Employee">
		select * from tbl_employee where id=#{id}
	</select>
	
	<!--public List<Employee> getEmps();  -->
	<select id="getEmps" resultType="com.test.springmvc.bean.Employee">
		select * from tbl_employee
	</select>
</mapper>