MyBatis

MyBatis简介

  • MyBatis 本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了googlecode,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。
  • MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  • 对jdbc的封装框架有哪些:Hibernate,dbutils,jdbcTemplate[spring],mybatis
  • 原理:Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

JDBC代码存在的问题

数据库连接频繁开启和关闭,会严重影响数据库的性能。
代码中存在硬编码,分别是数据库部分的硬编码和SQL执行部分的硬编码。

package com.wuzy.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import com.wuzy.bean.User;

public class Test {

	// JDBC driver name and database URL
	static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
	static final String DB_URL = "jdbc:mysql://10.17.152.149:3306/picture";
	// Database credentials
	static final String USER = "picture";
	static final String PASS = "122122";

	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		try {
			Class.forName(JDBC_DRIVER);

			conn = DriverManager.getConnection(DB_URL, USER, PASS);

			stmt = conn.createStatement();
			String sql;
			sql = "SELECT id, username, sex FROM user";
			ResultSet rs = stmt.executeQuery(sql);
			List<User> list = new ArrayList<User>();
			while (rs.next()) {
				int id = rs.getInt("id");
				String username = rs.getString("username");
				String sex = rs.getString("sex");

				User user = new User();
				user.setId(id);
				user.setUsername(username);
				user.setSex(sex);
				list.add(user);
			}
			System.out.println(list);
		} catch (SQLException se) {
			se.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (stmt != null)
					stmt.close();
			} catch (SQLException se2) {
			}
			try {
				if (conn != null)
					conn.close();
			} catch (SQLException se) {
				se.printStackTrace();
			}
		}
	}
}

MyBatis的框架核心

  • mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的 信息。
  • mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
  • 通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
  • SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
  • Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括HashMap集合对象、POJO对象类型。

Mybatis开发

  1. 导包
    在这里插入图片描述
  2. 添加log4j.properties
    Mybatis使用的日志包是log4j的,所以需要添加log4j.properties。
    在classpath下创建log4j.properties如下:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

日志级别在开发阶段设置成DEBUG,在生产阶段设置成INFO或者ERROR。
3. 编写配置文件
主配置文件(SqlMapConfig.xml)
在classpath(src)下,创建SqlMapConfig.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>

	<properties resource="db.properties" />


	<!--配置别名 -->
	<typeAliases>
		<!--<typeAlias type="com.wuzy.model.User" alias="user"></typeAlias> -->

		<!--指定包名,别名就是类名,第一个小写 User 别名就是user -->
		<package name="com.wuzy.bean"></package>
		<package name="com.wuzy.vo"></package>
	</typeAliases>

	<!-- 配置mybatis的环境信息 -->
	<environments default="development">
		<environment id="development">
			<!-- 配置JDBC事务控制,由mybatis进行管理 -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 配置数据源,采用dbcp连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="${driverClass}" />
				<property name="url" value="${url}" />
				<property name="username" value="${name}" />
				<property name="password" value="${password}" />
			</dataSource>
		</environment>
	</environments>

	<!--告诉mybatis加载映射文件 -->
	<mappers>
		<mapper resource="com/wuzy/sqlmap/user.xml"></mapper>
		<!--第一种:写映射文件的名字 -->
		<!-- <mapper resource="com/wuzy/mapper/UserMapper.xml"></mapper> -->

		<!--第二种:写类名,一定要有个映射文件与之对应 如果没有,那么在UserMapper要声明注解  -->
		<!-- <mapper class="com.wuzy.mapper.UserMapper"></mapper> -->

		<!--第三种:可以写包名  xml文件名需要和接口名一样  -->
		<!-- <package name="com.wuzy.mapper"></package> -->

	</mappers>
</configuration>

映射文件

<?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="user">
	<!--根据id查询 -->
	<!-- [id]:statement的id,要求在命名空间内唯一 [parameterType]:入参的java类型 [resultType]:查询出的单条结果集对应的java类型 
		[#{}]: 表示一个占位符? [#{id}]:表示该占位符待接收参数的名称为id。 注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义 -->
	<select id="findUserById" parameterType="int"
		resultType="com.wuzy.bean.User">
		SELECT * FROM user WHERE id = #{a}
	</select>

	<!-- [${}]:表示拼接SQL字符串 [${value}]:表示要拼接的是简单类型参数。 注意: 简单类型:int,byte,... string 
		1、如果参数为简单类型时,${}里面的参数名称必须为value 2、${}会引起SQL注入,一般情况下不推荐使用。但是有些场景必须使用${},比如order 
		by ${colname} -->
	<select id="findUserByName" parameterType="String"
		resultType="com.wuzy.bean.User">
		SELECT * FROM user WHERE username LIKE '%${value}%'
	</select>

	<!--插入数据 这里的占位是写模型的属性 -->
	<insert id="insertUser" parameterType="com.wuzy.bean.User">
		INSERT INTO user (username,sex,birthday,address)
		VALUE (#{username},#{sex},#{birthday},#{address});
	</insert>

	<!--删除 -->
	<delete id="deleteUser" parameterType="int">
		DELETE FROM user where id = #{id};
	</delete>


	<!--更新 -->
	<update id="updateUser" parameterType="com.wuzy.bean.User">
		UPDATE user SET address = #{address},sex = #{sex}
		WHERE id = #{id}
	</update>


	<!--插入时自动返回主键id -->
	<insert id="insertUser2" parameterType="com.wuzy.bean.User">
		<!-- [selectKey标签]:通过select查询来生成主键 [keyProperty]:指定存放生成主键的属性 [resultType]:生成主键所对应的Java类型 
			[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句 [last_insert_id]:MySQL的函数,要配合insert语句一起使用 -->
		<selectKey keyProperty="id" resultType="int" order="AFTER">
			SELECT LAST_INSERT_ID()
		</selectKey>
		INSERT INTO user (username,sex,birthday,address)
		VALUE (#{username},#{sex},#{birthday},#{address});
	</insert>
</mapper>

测试代码

package com.wuzy.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

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.wuzy.bean.User;

public class Test1 {

	@Test
	public void test1() throws IOException {
//        a)读取配置文件;
		InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");

		// b)通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

		// c)通过SqlSessionFactory创建SqlSession。
		SqlSession session = sessionFactory.openSession();

//        d)调用SqlSession的操作数据库方法。
		// 查询一条结果
		User user = session.selectOne("findUserById", 10);
		System.out.println(user);

		// 查询多条结果
		List<User> users = session.selectList("findUserByName", "张");
		System.out.println(users);
//        关闭SqlSession。
		session.commit();
	}
}
  1. Mybatis增删改查
    插入数据
<!--插入时自动返回主键id -->
<insert id="insertUser2" parameterType="com.wuzy.bean.User">
	<!-- [selectKey标签]:通过select查询来生成主键 [keyProperty]:指定存放生成主键的属性 [resultType]:生成主键所对应的Java类型 
		[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句 [last_insert_id]:MySQL的函数,要配合insert语句一起使用 -->
	<selectKey keyProperty="id" resultType="int" order="AFTER">
		SELECT LAST_INSERT_ID()
	</selectKey>
	INSERT INTO user (username,sex,birthday,address)
	VALUE (#{username},#{sex},#{birthday},#{address});
</insert>
session.insert("insertUser", new User("小强", "男", new Date(), "广州"));
session.commit();

删除数据

<!--删除 -->
<delete id="deleteUser" parameterType="int">
	DELETE FROM user where id = #{id};
</delete>
session.delete("deleteUser", 20);
session.commit();

修改数据

<!--更新 -->
<update id="updateUser" parameterType="com.wuzy.bean.User">
	UPDATE user SET username = #{username},sex = #{sex}
	WHERE id = #{id}
</update>
User user = new User();
		user.setId(20);
		user.setSex("女");
		user.setUsername("刘亦菲");
		
		session.update("updateUser", user);
		session.commit();

查询数据
查询单条selectOne

<select id="findUserById" parameterType="int"
	resultType="com.wuzy.bean.User">
	SELECT * FROM user WHERE id = #{a}
</select>
session.selectOne("findUserById", 20);
session.commit();

查询多条selectList

<select id="findUserByName" parameterType="String"
	resultType="com.wuzy.bean.User">
	SELECT * FROM user WHERE username LIKE '%${value}%'
</select>
session.selectList("findUserByName", "张");
session.commit();

5.主键返回之MySQL自增主键
MySQL自增主键,是指在insert之前MySQL会自动生成一个自增的主键。
我们可以通过MySQL的函数获取到刚插入的自增主键:
LAST_INSERT_ID()
这个函数是在insert语句之后去调用。

<insert id="insertUser" parameterType="com.wuzy.bean.User">
		<!-- 
			[selectKey标签]:通过select查询来生成主键
			[keyProperty]:指定存放生成主键的属性
			[resultType]:生成主键所对应的Java类型
			[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句
			[last_insert_id]:MySQL的函数,要配合insert语句一起使用 -->
		<selectKey keyProperty="id" resultType="int" order="AFTER">
			SELECT LAST_INSERT_ID()
		</selectKey>
		<!-- 如果主键的值是通过MySQL自增机制生成的,那么我们此处不需要再显示的给ID赋值 -->
		INSERT INTO USER (username,sex,birthday,address) 
		VALUES(#{username},#{sex},#{birthday},#{address})
</insert>

6.主键返回之MySQL自增UUID

<insert id="insertUser" parameterType="com.gyf.domain.User">
	<selectKey keyProperty="id" resultType="String" order="BEFORE">
		SELECT UUID()
	</selectKey>
	INSERT INTO USER (username,sex,birthday,address) 
	VALUES(#{username},#{sex},#{birthday},#{address})
</insert>

7.总结

parameterType和resultType
parameterType指定输入参数的java类型,可以填写别名或Java类的全限定名。
resultType指定输出结果的java类型,可以填写别名或Java类的全限定名。

#{}和${}
#{}:相当于预处理中的占位符?。
#{}里面的参数表示接收java输入参数的名称。
#{}可以接受HashMap、POJO类型的参数。
当接受简单类型的参数时,#{}里面可以是value,也可以是其他。
#{}可以防止SQL注入。
${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。
${}会引起SQL注入,所以要谨慎使用。
${}可以接受HashMap、POJO类型的参数。
当接受简单类型的参数时,${}里面只能是value。

selectOne和selectList
selectOne:只能查询0或1条记录,大于1条记录的话,会报错:
selectList:可以查询0或N条记录

Mybatis的dao方式开发(一般不用)

dao层代码

package com.wuzy.dao;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.wuzy.bean.User;

public class UserDaoImpl implements UserDao {
	
	
	private SqlSessionFactory ssf;

	public UserDaoImpl() {
	}

	public UserDaoImpl(SqlSessionFactory ssf) {
		this.ssf = ssf;
	}

	@Override
	public void save(User user) {

		// 获取session
		SqlSession session = ssf.openSession();

		// 插入数据
		session.insert("insertUser", user);

		session.commit();
		session.close();
	}

	@Override
	public User findUserById(int id) {
		// 获取session
		SqlSession session = ssf.openSession();

		// 插入数据
		User user = session.selectOne("findUserById", id);

		session.close();
		return user;
	}
}

测试

package com.wuzy.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

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

import com.wuzy.bean.User;
import com.wuzy.dao.UserDao;
import com.wuzy.dao.UserDaoImpl;

public class Test2 {

	SqlSessionFactory sessionFactory;
    @Before
    public void before() throws IOException {
        System.out.println("before.....获取session");
//        a)读取配置文件;
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");

        //b)通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
        sessionFactory = new SqlSessionFactoryBuilder().build(is);

    }
    
    @Test
    public void test1() throws IOException {

        //调用dao
        //1.创建dao
        UserDao userDao = new UserDaoImpl(sessionFactory);

        User user1 =  userDao.findUserById(1);

        System.out.println(user1);
        User user2 = new User("旺财","女",new Date(),"香港");
        userDao.save(user2);
    }
}

Mybati的mapper代理方式开发

Mapper代理的开发方式,程序员只需要编写mapper接口(相当于dao接口)即可。Mybatis会自动的为mapper接口生成动态代理实现类。
不过要实现mapper代理的开发方式,需要遵循一些开发规范。

  • mapper开发规范
  1. mapper接口的全限定名要和mapper映射文件的namespace的值相同。
  2. mapper接口的方法名称要和mapper映射文件中的statement的id相同;
  3. mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
  4. mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致;
  5. 通过规范式的开发mapper接口,可以解决原始dao开发当中存在的问题:
    模板代码已经去掉;
    剩下去不掉的操作数据库的代码,其实就是一行代码。这行代码中硬编码的部分,通过第一和第二个规范就可以解决。
  • mapper接口
package com.wuzy.mapper;

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

import com.wuzy.bean.User;
import com.wuzy.vo.UserQueryVO;

public interface UserMapper {

	/**
	 *
	 * @param user
	 * @return 受影响的行数
	 */
	public int save(User user);

	public User findUserById(int id);

	public List<User> findUserByUserQueryVo(UserQueryVO vo);

	public List<User> findUserByMap(Map<String, Object> map);
}
  • mapper.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.wuzy.mapper.UserMapper">

	<insert id="save" parameterType="user">
		INSERT INTO user
		(username,sex,birthday,address)
		VALUE
		(#{username},#{sex},#{birthday},#{address})
	</insert>

	<select id="findUserById" parameterType="int" resultType="user">
		SELECT
		* FROM user WHERE id = #{id}
	</select>

	<!--通过包装类查询用户 -->
	<select id="findUserByUserQueryVo" parameterType="userQueryVO"
		resultType="user">
		SELECT u.* FROM user u WHERE u.id = #{user.id}

	</select>

	<!--通过Map查询数据 -->
	<select id="findUserByMap" parameterType="hashmap"
		resultType="user">
		SELECT u.* FROM user u WHERE username LIKE '%${username}%'
		AND sex = #{sex}

	</select>

	<select id="findUserByName" parameterType="String"
		resultType="user">
		SELECT * FROM user WHERE username LIKE '%${value}%'
	</select>
</mapper>
  • 测试
package com.wuzy.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.After;
import org.junit.Before;
import org.junit.Test;

import com.wuzy.mapper.UserMapper;

public class Test3 {
	SqlSession session;

	@Before
	public void before() throws IOException {
		System.out.println("before.....获取session");
//	        a)读取配置文件;
		InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");

		// b)通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

		session = sessionFactory.openSession();
	}

	@After
	public void after() {
		session.close();
	}

	@Test
	public void test1() throws IOException {

		UserMapper userMapper = session.getMapper(UserMapper.class);

		// 获取数据
		System.out.println(userMapper.findUserById(1));
	}
}

Mybatis主配置文件中的其他配置

别名配置

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal

自定义别名

<!--配置别名 -->
<typeAliases>
	<!--<typeAlias type="com.wuzy.bean.User" alias="user"></typeAlias> -->

	<!--指定包名,别名就是类名,第一个小写 User 别名就是user -->
	<package name="com.wuzy.bean"></package>
	<package name="com.wuzy.vo"></package>
</typeAliases>

mappers

<mapper resource=’’/>
使用相对于类路径的资源
如:<mapper resource="sqlmap/User.xml" />

<mapper url=’’/> 【不用】
使用完全限定路径
如:<mapper url="file:///D:\workspace_spingmvc\mybatis_01\config\sqlmap\User.xml" />

<mapper class=’’/>
使用mapper接口的全限定名
如:<mapper class="cn.wuzy.mapper.UserMapper"/>

也可使用注解开发,把xml文件删除
@Insert("INSERT INTO user (username,sex,birthday,address) VALUE (#{username},#{sex},#{birthday},#{address})")
	public int save(User user);
注意:此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下;

<package name=’’/>(推荐)
注册指定包下的所有映射文件
如:<package name="cn.wuzy.mapper"/>

注意:此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下;

Mybatis映射文件

  • 输入映射ParameterType
    指定输入参数的java类型,可以使用别名或者类的全限定名。它可以接收简单类型,POJO对象、HashMap。
  • 传递简单类型
<select id="findUserById" parameterType="int" resultType="user">
	SELECT
	* FROM user WHERE id = #{id}
</select>
  • 传递POJO对象
<insert id="save" parameterType="user">
	INSERT INTO user
	(username,sex,birthday,address)
	VALUE
	(#{username},#{sex},#{birthday},#{address})
</insert>
  • 传递hashmap
<!--通过Map查询数据 -->
   <select id="findUserByMap" parameterType="hashmap"
   	resultType="user">
   	SELECT u.* FROM user u WHERE username LIKE '%${username}%'
   	AND sex = #{sex}

   </select>
  • 传递POJO包装对象
<select id="findUserByUserQueryVo" parameterType="userQueryVO"
   resultType="user">
   SELECT u.* FROM user u WHERE u.id = #{user.id}
</select>
package com.wuzy.vo;

import com.wuzy.bean.Order;
import com.wuzy.bean.User;

public class UserQueryVO {
   private User user;

   private Order order;
   public User getUser() {
       return user;
   }

   public void setUser(User user) {
       this.user = user;
   }

   public Order getOrder() {
       return order;
   }

   public void setOrder(Order order) {
       this.order = order;
   }
}

开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对
象传递输入参数。
需求
综合查询用户信息,需要传入查询条件复杂,比如(用户信息、订单信息、商品信息)。
vo:键值对对象,相对于kv
po:persist object 持久化对象
pojo:简单的java对象
entity:实体

  • 输出映射 resultType/resultMap
    • resultType
      使用resultType进行结果映射时,查询的列名和映射的pojo属性名完全一致,该列才能映射成功。
      如果查询的列名和映射的pojo属性名全部不一致,则不会创建pojo对象;
      如果查询的列名和映射的pojo属性名有一个一致,就会创建pojo对象。
      • 输出简单类型
        当输出结果只有一列时,可以使用ResultType指定简单类型作为输出结果类型。
        案例:
      • 输出一个count(*)
        	<!-- 查询用户的个数 -->
        	<select id="findUserCount" parameterType="userQueryVO"
        	resultType="int">
        	SELECT COUNT(*) FROM user WHERE sex = #{user.sex}
        	</select>
        
         	public int findUserCount(UserQueryVO vo);
        
        	@Test
        	public void test1() throws IOException {
        		UserMapper userMapper = session.getMapper(UserMapper.class);
        
        	// 通过模型的包装类来查询
        	UserQueryVO query = new UserQueryVO();
        
        	User user = new User();
        	user.setSex("2");// 男性
        	query.setUser(user);
        	int count = userMapper.findUserCount(query);
        	System.out.println("男性的用户人数:" + count);
        }
        
      • 输出POJO单个对象
        <select id="findUserById" parameterType="int" resultType="user">
        SELECT * FROM user WHERE id = #{id}
        </select>
        
        public User findUserById(int id);
        
        @Test
        public void test() throws IOException {
        	UserMapper userMapper = session.getMapper(UserMapper.class);
        	User user = userMapper.findUserById(20);
        	System.out.println("男性的用户人数:" + user);
        
        }
        
      • 输出POJO列表
                <select id="findUserList" parameterType="userQueryVO"
        		resultType="user">
        		SELECT * FROM user
        		<where>
        			<include refid="select_user_where" />
        		</where>
        	</select>
        	<sql id="select_user_where">
        		<if test="user != null">
        			<if test="user.sex != null and user.sex != ''">
        				sex = #{user.sex}
        			</if>
        			<if test="user.username != null and user.username != ''">
        				and username LIKE '%${user.username}%'
        			</if>
        			<if test="user.address != null and user.address != ''">
        				and address LIKE '%${user.address}%'
        			</if>
        		</if>
        	</sql>
        
        public List<User> findUserList(UserQueryVO vo);
        
        @Test
        public void test() throws IOException {
        
        	UserMapper userMapper = session.getMapper(UserMapper.class);
        
        	// 通过模型的包装类来查询
        	UserQueryVO query = new UserQueryVO();
        
        	User user = new User();
        	user.setSex("2");// 男性
        	query.setUser(user);
        
        	List<User> list = userMapper.findUserList(query);
        	System.out.println("男性的用户人数:" + list);
        
        }
        
      • 总结
        输出单个pojo对象和pojo列表时,mapper映射文件中的resultType的类型是一样的,mapper接口的方法返回值不同。
        同样的mapper映射文件,返回单个对象和对象列表时,mapper接口在生成动态代理的时候,会根据返回值的类型,决定调用selectOne方法还是selectList方法。
    • resultMap
      如果查询出来的列名和属性名不一致,通过定义一个resultMap将列名和pojo属性名之间作一个映射关系。
      1、 定义resultMap
      2、使用resultMap作为statement的输出映射类型
      <select id="findUserByIdResultMap" parameterType="int"
      	resultMap="userResultMap">
      	SELECT
      	id id_,
      	username username_,
      	sex sex_,
      	birthday birthday_,
      	address address_
      	FROM user WHERE id = #{id}
      </select>
      
      public User findUserByIdResultMap(int userId);
      
      @Test
      public void test2() throws IOException {
      
      	UserMapper userMapper = session.getMapper(UserMapper.class);
      
      	User user = userMapper.findUserByIdResultMap(1);
      	System.out.println("用户数据:" + user);
      
      }
      

5 动态SQL

  • if和where

    • If标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上。
      注意:用if进行判断是否为空时,不仅要判断null,也要判断空字符串‘’;
    • Where标签:会去掉条件中的第一个and符号。
          <select id="findUserList" parameterType="userQueryVO" resultType="user">
          /*性别和名字*/
          SELECT * FROM user
      
          <where>
              <if test="user != null">
              <if test="user.sex != null and user.sex != ''">
                  sex = #{user.sex}
              </if>
              <if test="user.username != null and user.username != ''">
                  and username LIKE '%${user.username}%'
              </if>
              <if test="user.address != null and user.address != ''">
                  and address LIKE '%${user.address}%'
              </if>
          </if>
          </where>
      </select>
      
           public List<User> findUserList(UserQueryVO vo);
      
      @Test
      public void test3() throws IOException {
      
      	UserMapper userMapper = session.getMapper(UserMapper.class);
      
      	// 查询条件
      	UserQueryVO query = new UserQueryVO();
      
      	User user = new User();
      	user.setSex("1");// 男性
      	user.setUsername("张");
      	query.setUser(user);
      
      	List<User> users = userMapper.findUserList(query);
      	System.out.println(users);
      }
      
  • SQL片断

    <sql id="select_user_where">
           <if test="user != null">
               <if test="user.sex != null and user.sex != ''">
                   sex = #{user.sex}
               </if>
               <if test="user.username != null and user.username != ''">
                   and username LIKE '%${user.username}%'
               </if>
               <if test="user.address != null and user.address != ''">
                   and address LIKE '%${user.address}%'
               </if>
           </if>
       </sql>
       <select id="findUserList" parameterType="userQueryVO" resultType="user">
           /*性别和名字*/
           SELECT * FROM user
    
           <where>
               <include refid="select_user_where"/>
           </where>
       </select> 
    
       public List<User> findUserList(UserQueryVO vo);
    
    @Test
    public void test3() throws IOException {
    
    	UserMapper userMapper = session.getMapper(UserMapper.class);
    
    	// 查询条件
    	UserQueryVO query = new UserQueryVO();
    
    	User user = new User();
    	user.setSex("1");// 男性
    	user.setUsername("张");
    	query.setUser(user);
    
    	List<User> users = userMapper.findUserList(query);
    	System.out.println(users);
    }
    
  • foreach 遍历

    <select id="findUserByIds" parameterType="userQueryVO" resultType="user">
        <!--性别和名字 SELECT * FROM user WHERE id in (1,2,3) -->
       SELECT * FROM user
       <where>
           <if test="ids != null and ids.size > 0">
               <!--
               collection:集合,写集合属性
               item:遍历接收变量
               open:遍历开始
               close:遍历结束
               separator:拼接格式
               for(Integer id : ids){
               }
               -->
                <foreach collection="ids" item="id" open="id in(" close=")" separator=",">
                    ${id}
                </foreach>
            </if>
        </where>
    </select>
    <!-- 5.参数是数组
        如果参数是数组的话,parameterType可以写全名【java.util.List】,也可以写别名
        遍历或者判断的时候,都用list变量
    -->
    <select id="findUserByIds2" parameterType="list" resultType="user">
        <!--性别和名字 SELECT * FROM user WHERE id in (1,2,3) -->
        SELECT * FROM user
        <where>
            <if test="list != null and list.size > 0">
                <foreach collection="list" item="id" open="id in(" close=")" separator=",">
                    ${id}
                </foreach>
            </if>
        </where>
    </select>
    
    /* 查找多个id的用户数据 */
    public List<User> findUserByIds(UserQueryVO vo);
    
    public List<User> findUserByIds2(List<Integer> ids);
    
    @Test
    public void test4() throws IOException {
    
    	UserMapper userMapper = session.getMapper(UserMapper.class);
    
    	// 查询条件
    	UserQueryVO query = new UserQueryVO();
    	List<Integer> ids = new ArrayList<Integer>();
    	ids.add(1);
    	ids.add(10);
    	ids.add(16);
    	query.setIds(ids);
    
    	List<User> users = userMapper.findUserByIds(query);
    	System.out.println(users);
    }
    
    @Test
    public void test5() throws IOException {
    
    	UserMapper userMapper = session.getMapper(UserMapper.class);
    
    	// 查询条件
    	List<Integer> ids = new ArrayList<Integer>();
    	ids.add(1);
    	ids.add(10);
    	ids.add(16);
    
    	List<User> users = userMapper.findUserByIds2(ids);
    	System.out.println(users);
    }
    

mybatis与hibernate的区别

  • Mybatis技术特点
    好处:
    1. 通过直接编写SQL语句,可以直接对SQL进行性能的优化;
    2. 学习门槛低,学习成本低。只要有SQL基础,就可以学习mybatis,而且很容易上手;
    3. 由于直接编写SQL语句,所以灵活多变,代码维护性更好。
    缺点:
    1. 不能支持数据库无关性,即数据库发生变更,要写多套代码进行支持,移植性不好。
    a)Mysql:limit
    b)Oracle:rownum
    2.需要编写结果映射
  • Hibernate技术特点
    好处:
    1. 标准的orm框架,程序员不需要编写SQL语句。
    2. 具有良好的数据库无关性,即数据库发生变化的话,代码无需再次编写。
    a)以后,mysql数据迁移到oracle,只需要改方言配置
    缺点:
    1. 学习门槛高,需要对数据关系模型有良好的基础,而且在设置OR映射的时候,需要考虑好性能和对象模型的权衡。
    2.程序员不能自主的去进行SQL性能优化
  • Mybatis应用场景
    需求多变的互联网项目,例如电商项目。
  • Hibernate应用场景
    需求明确、业务固定的项目,例如OA项目、ERP项目等。

关联查询

表关系

  • user和orders:
    User 与orders:一个用户可以创建多个订单,一对多
    Orders 与 user:多个订单只由一个用户创建,多对一
  • orders和orderdetail:
    Orders 与 orderdetail:一个订单可以包括多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系
    orderdetail 与orders:多个订单明细包括在一个订单中, 多对一
  • orderdetail和items:
    Orderdetail 与 items:多个订单明细只对应一个商品信息,多对一
    Items 与 orderdetail:一个商品可以包括在多个订单明细 ,一对多

一对一查询

  1. 复杂查询时,单表对应的po类已不能满足输出结果集的映射。所以要根据需求建立一个扩展类来作为resultType的类型。
    需求:

    #查找某个定单id的信息,包括用户名字和地址
    SELECT o.*,u.username,u.address FROM orders o,user u
    WHERE o.user_id = u.id AND o.id = 3
    
  2. 编写订单的扩展类

      package com.wuzy.bean;
      
      public class OrdersExt extends Orders{
      
          private String username;
          private String address;
      
          public String getUsername() {
              return username;
          }
      
          public void setUsername(String username) {
              this.username = username;
          }
      
          public String getAddress() {
              return address;
          }
      
          public void setAddress(String address) {
              this.address = address;
          }
      
          @Override
          public String toString() {
              return "OrdersExt{" +
                      "username='" + username + '\'' +
                      ", address='" + address + '\'' +
                      '}' + super.toString();
          }
      }
      
    
  3. 声明订单接口

    public OrdersExt findOrderById(int id);
    
  4. 编写xml文件

      <select id="findOrderById" parameterType="int"
      	resultType="ordersExt">
      	SELECT
      	o.*,u.username,u.address
      	FROM
      	orders o,user u
      	WHERE
      	o.user_id = u.id
      	AND o.id = #{id}
      </select>
    
  5. 测试代码

    /**
       * 一对一 : 写个定单的扩展类
       * 
       * @throws IOException
       */
      @Test
      public void test6() throws IOException {
    
      	OrderMapper mapper = session.getMapper(OrderMapper.class);
    
      	OrdersExt ordersExt = mapper.findOrderById(3);
    
      	System.out.println(ordersExt);
      }
    
  6. resultMap实现

    1. 订单中包含user对象
      package com.wuzy.bean;
      
      import java.util.Date;
      import java.util.List;
      
      public class Orders {
          private Integer id;
          private Integer user_id;
          private String note;//备注
          private String number;
          private Date createtime;//写意的创建时间
      
          private User user;//定单所属的用户
      
          /* 一对多数据封装*/
          private List<OrderDetail> orderDetails;
      
          public List<OrderDetail> getOrderDetails() {
              return orderDetails;
          }
      
          public void setOrderDetails(List<OrderDetail> orderDetails) {
              this.orderDetails = orderDetails;
          }
      
          public User getUser() {
              return user;
          }
      
          public void setUser(User user) {
              this.user = user;
          }
      
          @Override
          public String toString() {
              return "Orders{" +
                      "id=" + id +
                      ", user_id=" + user_id +
                      ", note='" + note + '\'' +
                      ", number='" + number + '\'' +
                      ", createtime=" + createtime +
                      '}';
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public Integer getUser_id() {
              return user_id;
          }
      
          public void setUser_id(Integer user_id) {
              this.user_id = user_id;
          }
      
          public String getNote() {
              return note;
          }
      
          public void setNote(String note) {
              this.note = note;
          }
      
          public Date getCreatetime() {
              return createtime;
          }
      
          public void setCreatetime(Date createtime) {
              this.createtime = createtime;
          }
      
          public String getNumber() {
              return number;
          }
      
          public void setNumber(String number) {
              this.number = number;
          }
      }
      
    2. 定义接口
      public Orders findOrderById2(int id);
      
    3. 编写xml
      <!-- =============== 一对一 ================= -->
      <!--如果模型里有模型,使用resultMap -->
      <resultMap id="orderRslMap" type="orders">
      	<!-- 往orders的模型匹配数据 -->
      	<id column="id" property="id"></id>
      	<id column="note" property="note"></id>
      	<id column="number" property="number"></id>
      	<id column="createtime" property="createtime"></id>
      
      	<!-- 往orders的user匹配数据 模型里有模型,使用association来配置 -->
      	<association property="user" javaType="user">
      		<id column="user_id" property="id"></id>
      		<id column="username" property="username"></id>
      		<id column="address" property="address"></id>
      	</association>
      </resultMap>
      
      <select id="findOrderById2" parameterType="int"
      	resultMap="orderRslMap">
      	SELECT
      	o.*,u.username,u.address
      	FROM
      	orders o,user u
      	WHERE
      	o.user_id = u.id
      	AND o.id = #{id}
      </select>
      
    4. 测试代码
      /**
       * 一对一 : 模型里有模型
       * 
       * @throws IOException
       */
      @Test
      public void test7() throws IOException {
      
      	OrderMapper mapper = session.getMapper(OrderMapper.class);
      
      	Orders order = mapper.findOrderById2(3);
      	System.out.println(order);
      	System.out.println(order.getUser());
      }
      

一对多查询

需求:
根据定单ID查找定单信息、用户信息和定单明细信息

Select
			orders.id,
			orders.user_id,
			orders.number,
			orders.createtime,
			orders.note,
			user.username,
			user.address,
			orderdetail.id detail_id,
			orderdetail.items_id,
			orderdetail.items_num
		from 
			orders,user,orderdetail
		where 
			orders.user_id = user.id 
			and orders.id = orderdetail.orders_id
  			and orders.id = #{?};
SELECT 
	o.*,
	u.username,
	u.address,
	od.id detail_id,
  od.items_id,
  od.items_num
FROM 
	orders o,
	user u,
	orderdetail od
WHERE 
	o.user_id = u.id 
  AND o.id = od.orders_id
	AND o.id = 3
  • 在Orders中添加定单明细
 package com.wuzy.bean;

 import java.util.Date;
import java.util.List;

public class Orders {
    private Integer id;
    private Integer user_id;
    private String note;//备注
    private String number;
    private Date createtime;//写意的创建时间

    private User user;//定单所属的用户

    /* 一对多数据封装*/
    private List<OrderDetail> orderDetails;

    public List<OrderDetail> getOrderDetails() {
        return orderDetails;
    }

    public void setOrderDetails(List<OrderDetail> orderDetails) {
        this.orderDetails = orderDetails;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", user_id=" + user_id +
                ", note='" + note + '\'' +
                ", number='" + number + '\'' +
                ", createtime=" + createtime +
                '}';
    }

    public Integer getId() {
        return id;
    }

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

    public Integer getUser_id() {
        return user_id;
    }

    public void setUser_id(Integer user_id) {
        this.user_id = user_id;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public Date getCreatetime() {
        return createtime;
    }

    public void setCreatetime(Date createtime) {
        this.createtime = createtime;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }
}
  • 编写mapper接口
public Orders findOrderById3(int id);
  • 编写xml
<!-- ================一对多================== -->
	<resultMap id="orderRslMap3" type="orders">
		<!-- 往orders的模型匹配数据 -->
		<id column="id" property="id"></id>
		<id column="note" property="note"></id>
		<id column="number" property="number"></id>
		<id column="createtime" property="createtime"></id>

		<!-- 往orders的user匹配数据 模型里有模型,使用association来配置 -->
		<association property="user" javaType="user">
			<id column="user_id" property="id"></id>
			<id column="username" property="username"></id>
			<id column="address" property="address"></id>
		</association>

		<!-- 一对多匹配: 往orders的orderdetails 匹配数据 注意:集合里类型使用ofType,而不javaType -->
		<collection property="orderDetails" ofType="orderDetail">
			<id column="detail_id" property="id"></id>
			<id column="items_id" property="itemsId"></id>
			<id column="items_num" property="itemsNum"></id>
		</collection>
	</resultMap>


	<select id="findOrderById3" parameterType="int"
		resultMap="orderRslMap3">
		SELECT
		o.*,
		u.username,
		u.address,
		od.id detail_id,
		od.items_id,
		od.items_num
		FROM
		orders o,
		user u,
		orderdetail od
		WHERE
		o.user_id = u.id
		AND o.id = od.orders_id
		AND o.id = #{id}
	</select>
  • 测试代码
/**
 * 一对多 : 模型里有集合
 * 
 * @throws IOException
 */
@Test
public void test8() throws IOException {

	OrderMapper mapper = session.getMapper(OrderMapper.class);
	Orders order = mapper.findOrderById3(3);
	System.out.println(order);
	System.out.println(order.getUser());
	System.out.println(order.getOrderDetails());
}
  • 总结
    mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
    使用resultType实现:
    需要对结果集进行二次处理。将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。

多对多查询

需求:
查询用户信息及用户购买的商品信息,要求将关联信息映射到主pojo的pojo属性中

Select
	user.id,
	user.username,
	user.address,
	orders.id orders_id,
	orders.user_id,
	orders.number,
	orders.createtime,
	orders.note,
	orderdetail.id detail_id,
	orderdetail.items_id,
	orderdetail.items_num,
    items.name items_name,
    items.detail items_detail  
FROM
  USER,orders,orderdetail,items 
WHERE user.`id` = orders.`user_id` 
  AND orders.`id` = orderdetail.`orders_id` 
  AND orderdetail.`items_id` = items.`id`
SELECT 
  u.id,
	u.username,
	u.address,
	o.id order_id,
  o.number,
	o.createtime,
  o.note,
	od.id detail_id,
  od.items_id,
  od.items_num,
  it.name,
  it.price,
  it.detail
FROM 
	user u,
	orders o,
	orderdetail od,
  items it
WHERE 
	o.user_id = u.id 
  AND o.id = od.orders_id
  AND od.items_id = it.id;
  • 将用户信息映射到user中。
  • 在user类中添加订单列表属性List orderslist,将用户创建的订单映射到orderslist
  • 在Orders中添加订单明细列表属性List detailList,将订单的明细映射到detailList
  • 在Orderdetail中添加Items属性,将订单明细所对应的商品映射到Items

开发流程

  1. 修改user类
package com.wuzy.bean;

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

public class User implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1705381513476930984L;
	private int id;
	private String username;// 用户姓名
	private String sex;// 性别
	private Date birthday;// 生日
	private String address;// 地址

	private List<Orders> orderList;// 一个用户有多张定单

	public List<Orders> getOrderList() {
		return orderList;
	}

	public void setOrderList(List<Orders> orderList) {
		this.orderList = orderList;
	}

	public User() {
	}

	public User(String username, String sex, Date birthday, String address) {
		this.username = username;
		this.sex = sex;
		this.birthday = birthday;
		this.address = address;
	}

	public int getId() {
		return id;
	}

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

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
				+ address + "]";
	}

}
  • 编写接口
public List<User> findUserAndOrderInfo();
  • 编写xml
<!-- ==============查询用户信息及用户购买的商品信息============-->
    <resultMap id="userRslMap" type="user">
        <!-- 1.匹配user属性 -->
        <id column="id" property="id"></id>
        <result column="username" property="username"/>
        <result column="password" property="password"/>

        <!--2.匹配user的orderList-->
        <collection property="orderList" ofType="orders">
            <id column="order_id" property="id"></id>
            <result column="number" property="number"/>
            <result column="createtime" property="createtime"/>
            <result column="note" property="note"/>

            <!-- 3.匹配Orders里有orderDetails-->
            <collection property="orderDetails" ofType="orderDetail">
                <id column="detail_id" property="id"></id>
                <result column="items_id" property="itemsId"/>
                <result column="items_num" property="itemsNum"/>

                <!-- 4.配置定单详情的商品信息-->
                <association property="items" javaType="items">
                    <id column="items_id" property="id"/>
                    <result column="name" property="name"/>
                    <result column="price" property="price"/>
                    <result column="detail" property="detail"/>
                </association>
            </collection>
        </collection>
    </resultMap>

    <select id="findUserAndOrderInfo" resultMap="userRslMap">
        SELECT
            u.id,
            u.username,
            u.address,
            o.id order_id,
            o.number,
            o.createtime,
            o.note,
            od.id detail_id,
            od.items_id,
            od.items_num,
            it.name,
            it.price,
            it.detail
        FROM
            user u,
            orders o,
            orderdetail od,
          items it
        WHERE
            o.user_id = u.id
          AND o.id = od.orders_id
          AND od.items_id = it.id
    </select>
  • 测试代码
/**
 - 多对多
 - 
 - @throws IOException
 */
@Test
public void test9() throws IOException {

	UserMapper mapper = session.getMapper(UserMapper.class);

	List<User> users = mapper.findUserAndOrderInfo();
	for (User user : users) {
		System.out.println("用户信息:" + user);
		for (Orders order : user.getOrderList()) {
			System.out.println("定单信息:" + order);
			System.out.println("订单详情:");
			for (OrderDetail od : order.getOrderDetails()) {
				System.out.println(od + ":" + od.getItems());
			}

			System.out.println("------------------------------");
		}

	}
}

延时加载

延迟加载又叫懒加载,也叫按需加载。也就是说先加载主信息,在需要的时候,再去加载从信息。
在mybatis中,resultMap标签的association标签和collection标签具有延迟加载的功能。

  • mapper接口
/**
 * 懒加载定单的用户数据
 * 
 * @return
 */
public List<Orders> findOrderAndUserByLazyloading();
  • 编写xml文件
 <!-- ============= 懒加载 ================== -->
	<resultMap id="orderLazyloadingRslMap" type="orders">
		<id column="id" property="id" />
		<result column="note" property="note" />
		<result column="number" property="number" />
		<result column="createtime" property="createtime" />

		<!--配置查询 -->
		<association property="user"
			select="com.wuzy.mapper.UserMapper.findUserById" column="user_id" />
	</resultMap>
	<select id="findOrderAndUserByLazyloading"
		resultMap="orderLazyloadingRslMap">
		SELECT * FROM orders
	</select>
  • 开启懒加载
 <!--配置允许懒加载 -->
 <settings>
	<setting name="lazyLoadingEnabled" value="true" />
 </settings>
  • 测试
@Test
public void test10() throws IOException {

	OrderMapper mapper = session.getMapper(OrderMapper.class);

	List<Orders> list = mapper.findOrderAndUserByLazyloading();
	for (Orders order : list) {
		System.out.println("订单信息:");
		System.out.println(order);

		System.out.println("订单所属的客户:");
		System.out.println(order.getUser());
	}

}

mybatis整合spring

  • 向dao注入sessionFactory
    • spring配置文件
          <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
      		http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
      		http://www.springframework.org/schema/mvc
      		http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
      		http://www.springframework.org/schema/context
      		http://www.springframework.org/schema/context/spring-context-3.2.xsd
      		http://www.springframework.org/schema/aop
      		http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
      		http://www.springframework.org/schema/tx
      		http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
      
      
          <!-- 1.配置数据库,c3p0数据库连接池-->
          <context:property-placeholder location="classpath:db.properties"/>
      	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      	    <property name="driverClass" value="${jdbc.driverClass}"></property>
      	    <property name="jdbcUrl" value="${jdbc.url}"></property>
      	    <property name="user" value="${jdbc.name}"></property>
      	    <property name="password" value="${jdbc.password}"></property>
      	</bean>
          <!-- 2.配置会话工厂-->
          <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
              <property name="dataSource" ref="dataSource"/>
              <property name="configLocation" value="classpath:SqlMapConfig.xml"/>
          </bean>
      
      
          <!-- ===============配置dao的几种方式=================-->
          <!--  第一种 -->
          <!--3.传统配置dao,【现在不用】-->
          <bean id="userDao" class="com.wuzy.dao.UserDaoImpl">
              <!-- <property name="sqlSessionFactory" ref="sessionFactory"/> -->
              <constructor-arg name="ssf" ref="sessionFactory"></constructor-arg>
          </bean>
      </beans>
      
    • 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>
      
      	<properties resource="db.properties" />
      
      	<!--配置允许懒加载 -->
      	<settings>
      		<setting name="lazyLoadingEnabled" value="true" />
      	</settings>
      	<!--配置别名 -->
      	<typeAliases>
      		<!--<typeAlias type="com.gyf.model.User" alias="user"></typeAlias> -->
      
      		<!--指定包名,别名就是类名,第一个小写 User 别名就是user -->
      		<package name="com.wuzy.bean"></package>
      		<package name="com.wuzy.vo"></package>
      	</typeAliases>
      
      	<!-- 配置mybatis的环境信息 -->
      	<!-- <environments default="development">
      		<environment id="development">
      			配置JDBC事务控制,由mybatis进行管理
      			<transactionManager type="JDBC"></transactionManager>
      			配置数据源,采用dbcp连接池
      			<dataSource type="POOLED">
      				<property name="driver" value="${driverClass}" />
      				<property name="url" value="${url}" />
      				<property name="username" value="${name}" />
      				<property name="password" value="${password}" />
      			</dataSource>
      		</environment>
      	</environments> -->
      
      	<!--告诉mybatis加载映射文件 -->
      	<mappers>
      		<!--<mapper resource="com/gyf/sqlmap/User.xml"></mapper> -->
      
      		<!--第一种:写映射文件的名字 -->
      		<!--<mapper resource="com/gyf/mapper/UserMapper.xml"></mapper> -->
      
      		<!--第二种:写类名,一定要有个映射文件与之对应 如果没有,那么在UserMapper要声明注解 -->
      		<!--<mapper class="com.gyf.mapper.UserMapper"></mapper> -->
      
      		<!--第三种:可以写包名 -->
      		<package name="com.wuzy.mapper"></package>
      
      	</mappers>
      </configuration>
      
    • dao注入sessionFactory
          package com.wuzy.dao;
      
          import org.apache.ibatis.session.SqlSession;
          import org.apache.ibatis.session.SqlSessionFactory;
          
          import com.wuzy.bean.User;
          
          public class UserDaoImpl implements UserDao {
          
          	private SqlSessionFactory ssf;
          
          	public UserDaoImpl() {
          	}
          
          	public UserDaoImpl(SqlSessionFactory ssf) {
          		this.ssf = ssf;
          	}
          	
          	@Override
          	public void save(User user) {
          
          		// 获取session
          		SqlSession session = ssf.openSession();
          
          		// 插入数据
          		session.insert("insertUser", user);
          
          		session.commit();
          		session.close();
          	}
          	
          	@Override
          	public User findUserById(int id) {
          		// 获取session
          		SqlSession session = ssf.openSession();
          
          		// 插入数据
          		User user = session.selectOne("findUserById", id);
          
          		session.close();
          		return user;
          	}
          }
      
      
    • 测试
      @Test
      public void test1() {
      	// 1.加载spring的配置文件
      	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      
      	// 2.获取dao的bean
      	UserDao userDao = (UserDao) context.getBean("userDao");
      
      	// 3.调用dao方法
      	User user = userDao.findUserById(1);
      
      	System.out.println(user);
      
      }
      
  • mapper代理
    • mapper配置
      <select id="findUserById" parameterType="int" resultType="user">
          SELECT * FROM user WHERE id = #{id}
      </select>
      
    • mapper主配置文件
      <mappers>
      	<package name="com.wuzy.mapper"></package>
      </mappers>
      
    • spring配置
          <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
      		http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
      		http://www.springframework.org/schema/mvc
      		http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
      		http://www.springframework.org/schema/context
      		http://www.springframework.org/schema/context/spring-context-3.2.xsd
      		http://www.springframework.org/schema/aop
      		http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
      		http://www.springframework.org/schema/tx
      		http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
      
      
          <!-- 1.配置数据库,c3p0数据库连接池-->
          <context:property-placeholder location="classpath:db.properties"/>
      	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      	    <property name="driverClass" value="${jdbc.driverClass}"></property>
      	    <property name="jdbcUrl" value="${jdbc.url}"></property>
      	    <property name="user" value="${jdbc.name}"></property>
      	    <property name="password" value="${jdbc.password}"></property>
      	</bean>
          <!-- 2.配置会话工厂-->
          <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
              <property name="dataSource" ref="dataSource"/>
              <property name="configLocation" value="classpath:SqlMapConfig.xml"/>
          </bean>
      
      
          <!-- ===============配置dao的几种方式=================-->
          <!--  第一种 -->
          <!--3.传统配置dao,【现在不用】-->
          <!-- <bean id="userDao" class="com.wuzy.dao.UserDaoImpl">
              <property name="sqlSessionFactory" ref="sessionFactory"/>
              <constructor-arg name="ssf" ref="sessionFactory"></constructor-arg>
          </bean> -->
      
          <!-- 第二种 -->
          <!--4.由spring创建一个userMapper对象,使用工厂来创建-->
          <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
              <property name="sqlSessionFactory" ref="sessionFactory"/>
              <property name="mapperInterface" value="com.wuzy.mapper.UserMapper"/>
          </bean>
      
          <!-- 第三种 -->
          <!-- 批量创建mapper的bean对象
              内部会扫描指定包下的mapper,创建代理对象,名字就是类名,头字母改小写
          -->
          <!-- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
              <property name="basePackage" value="com.wuzy.mapper.UserMapper"/>
              <property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
          </bean> -->
      </beans>
      
    • 接口
      public interface UserDao {
          public User findUserById(int id);
      }
      
    • 测试
      @Test
      public void test2() {
      	// 1.加载spring的配置文件
      	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      
      	// 2.获取userMapper
      	UserMapper userMapper = (UserMapper) context.getBean("userMapper");
      
      	// 3.调用dao方法
      	User user = userMapper.findUserById(1);
      
      	System.out.println(user);
      
      }
      
  • spring扫描
        <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
              xmlns:context="http://www.springframework.org/schema/context"
              xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
              xsi:schemaLocation="http://www.springframework.org/schema/beans
       		http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       		http://www.springframework.org/schema/mvc
       		http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
       		http://www.springframework.org/schema/context
       		http://www.springframework.org/schema/context/spring-context-3.2.xsd
       		http://www.springframework.org/schema/aop
       		http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
       		http://www.springframework.org/schema/tx
       		http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
       
       
           <!-- 1.配置数据库,c3p0数据库连接池-->
           <context:property-placeholder location="classpath:db.properties"/>
       	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
       	    <property name="driverClass" value="${jdbc.driverClass}"></property>
       	    <property name="jdbcUrl" value="${jdbc.url}"></property>
       	    <property name="user" value="${jdbc.name}"></property>
       	    <property name="password" value="${jdbc.password}"></property>
       	</bean>
           <!-- 2.配置会话工厂-->
           <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
               <property name="dataSource" ref="dataSource"/>
               <!-- 别名 -->
               <property name="typeAliasesPackage" value="com.wuzy"></property>
               <!-- <property name="configLocation" value="classpath:SqlMapConfig.xml"/> -->
               <property name="mapperLocations" value="classpath*:com/wuzy/mapper/*Mapper.xml"></property>
           </bean>
       
       
           <!-- ===============配置dao的几种方式=================-->
           <!--  第一种 -->
           <!--3.传统配置dao,【现在不用】-->
           <!-- <bean id="userDao" class="com.wuzy.dao.UserDaoImpl">
               <property name="sqlSessionFactory" ref="sessionFactory"/>
               <constructor-arg name="ssf" ref="sessionFactory"></constructor-arg>
           </bean> -->
       
           <!-- 第二种 -->
           <!--4.由spring创建一个userMapper对象,使用工厂来创建-->
           <!-- <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
               <property name="sqlSessionFactory" ref="sessionFactory"/>
               <property name="mapperInterface" value="com.wuzy.mapper.UserMapper"/>
           </bean> -->
       
           <!-- 第三种 -->
           <!-- 批量创建mapper的bean对象
               内部会扫描指定包下的mapper,创建代理对象,名字就是类名,头字母改小写
           -->
           <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
               <property name="basePackage" value="com.wuzy.mapper"/>
               <property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
           </bean>
       
       
       
       </beans>
    
    测试代码
    @Test
    public void test2() {
    	// 1.加载spring的配置文件
    	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
    	// 2.获取userMapper
    	UserMapper userMapper = (UserMapper) context.getBean("userMapper");
    
    	// 3.调用dao方法
    	User user = userMapper.findUserById(1);
    
    	System.out.println(user);
    
    }
    
  • 10
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值