【Mybatis笔记--全面版】

Mybatis

Mybaits简介

  • Apache开源项目,迁移到Google。从ibatis到mybatis
  • 优秀的持久层框架,对jdbc操作数据库的步骤进行封装
  • 使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

JDBC编程问题总结

jdbc程序

public static void main(String[] args) {
	Connection connection = null;
	PreparedStatement preparedStatement = null;
	ResultSet resultSet = null;

	try {
		// 加载数据库驱动
		Class.forName("com.mysql.jdbc.Driver");

		// 通过驱动管理类获取数据库链接
		connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
		// 定义sql语句 ?表示占位符
		String sql = "select * from user where username = ?";
		// 获取预处理statement
		preparedStatement = connection.prepareStatement(sql);
		// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
		preparedStatement.setString(1, "王五");
		// 向数据库发出sql执行查询,查询出结果集
		resultSet = preparedStatement.executeQuery();
		// 遍历查询结果集
		while (resultSet.next()) {
			System.out.println(resultSet.getString("id") + "  " + resultSet.getString("username"));
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		// 释放资源
		if (resultSet != null) {
			try {
				resultSet.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (preparedStatement != null) {
			try {
				preparedStatement.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (connection != null) {
			try {
				connection.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

问题总结

  1. 数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。

  2. Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。

  3. 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。

  4. 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

Mybatis架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yiYqfnOV-1589804296294)(file:///C:\Users\dby\AppData\Local\Temp\ksohtml9016\wps1.png)]

Mybatis入门程序

  1. 下载Mybatis的jar包

  2. 业务需求

    1. 根据用户id查询一个用户
    2. 根据用户名称模糊查询用户列表、
    3. 添加用户
    4. 更新用户
    5. 删除用户
  3. 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
    
  4. SqlMapConfig.xml(和spring整合后,消失)



<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?characterEncoding=utf-8" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			dataSource>
		environment>
	environments>
    <mappers>
        <mapper resource="sqlmap/User.xml">mapper>
    mappers>
    
configuration>
  1. User.xml



<mapper namespace="test">
    
	
	
	
	<select id="queryUserById" parameterType="Integer"
		resultType="cn.itcast.mybatis.pojo.User">
		SELECT * FROM `user` WHERE id  = #{id}
	select>
    <select id="queryUserByUsername1" parameterType="String"
		resultType="cn.itcast.mybatis.pojo.User">
		SELECT * FROM `user` WHERE username LIKE #{username}
	select>
    
mapper>
  1. 测试程序
public class MybatisTest {
	private SqlSessionFactory sqlSessionFactory = null;

	@Before
	public void init() throws Exception {
		// 1. 创建SqlSessionFactoryBuilder对象
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

		// 2. 加载SqlMapConfig.xml配置文件
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");

		// 3. 创建SqlSessionFactory对象
		this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
	}

	@Test
	public void testQueryUserById() throws Exception {
		// 4. 创建SqlSession对象
		SqlSession sqlSession = sqlSessionFactory.openSession();

		// 5. 执行SqlSession对象执行查询,获取结果User
		// 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
		Object user = sqlSession.selectOne("queryUserById", 1);

		// 6. 打印结果
		System.out.println(user);

		// 7. 释放资源
		sqlSession.close();
	}
}

测试程序提取

// 1. 创建SqlSessionFactoryBuilder对象
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

		// 2. 加载SqlMapConfig.xml配置文件
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");

		// 3. 创建SqlSessionFactory对象
		this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);

		// 4. 创建SqlSession对象
		SqlSession sqlSession = sqlSessionFactory.openSession();

		// 5. 执行SqlSession对象执行查询,获取结果User
		// 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
		Object user = sqlSession.selectOne("queryUserById", 1);

		// 有时需要
		sqlSession.commit();
		// 6. 打印结果
		System.out.println(user);

Mybatis解决jdbc编程的问题

1、 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。

解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。

2、 Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3、 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。

4、 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

Mybatis和Hibernate的区别

Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。

总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

Mapper动态代理方式开发

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper接口开发遵循规则

  1. Mapper.xml文件中的namespace与mapper接口的类路径相同

  2. Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

  3. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同

  4. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

sqlMapConfig.xml

【整合后废弃】

<environments default="development">
		<environment id="development">
			
			<transactionManager type="JDBC" />
			
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			dataSource>
		environment>
	environments>

<properties resource="db.properties">
		
		
		<property name="jdbc.username" value="root123" />
		<property name="jdbc.password" value="root123" />
	properties>

<typeAliases>
		
		<typeAlias alias="user" type="cn.itcast.mybatis.pojo.User" />
		
		<package name="cn.itcast.mybatis.pojo" />
		<package name="其它包" />
	typeAliases>

使用相对于类路径的资源(现在的使用方式)

如:

使用mapper接口类路径

如:

注意:此种方法要求mapper接口名称[如UserMapper.java]和mapper映射文件名称[如UserMapper.xml]相同,且放在同一个目录中。

注册指定包下的所有mapper接口

如:

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

XxxMapper.xml

  • namespace:命名空间(加入命名空间后,访问方法用namespace.id

// 得到最后插入的id
<selectKey keyProperty="id" resultType="Integer" order="AFTER">
			select LAST_INSERT_ID()
		selectKey>

手动映射

OrderMapper.xml




<mapper namespace="cn.itcast.mybatis.mapper.OrderMapper">

	
	
	<resultMap type="Orders" id="orderResultMap">
		
		
		
		<id property="id" column="id" />

		
		<result property="userId" column="user_id" />
		<result property="number" column="number" />
		<result property="createtime" column="createtime" />
		<result property="note" column="note" />
	resultMap>

	
	<select id="queryOrderAll" resultMap="orderResultMap">
		SELECT id, user_id,
		number,
		createtime, note FROM `order`
	select>

mapper>
resultMap type="order" id="orderUserResultMap">
	<id property="id" column="id" />
	<result property="userId" column="user_id" />
	<result property="number" column="number" />
	<result property="createtime" column="createtime" />
	<result property="note" column="note" />

	
	
	
	<association property="user" javaType="User">
		
		<id property="id" column="user_id" />
		<result property="username" column="username" />
		<result property="address" column="address" />
	association>

resultMap>


<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
	SELECT
	o.id,
	o.user_id,
	o.number,
	o.createtime,
	o.note,
	u.username,
	u.address
	FROM
	`order` o
	LEFT JOIN `user` u ON o.user_id = u.id
select>
<resultMap type="user" id="userOrderResultMap">
	<id property="id" column="id" />
	<result property="username" column="username" />
	<result property="birthday" column="birthday" />
	<result property="sex" column="sex" />
	<result property="address" column="address" />

	
	<collection property="orders" javaType="list" ofType="order">
		
		<id property="id" column="oid" />
		<result property="number" column="number" />
		<result property="createtime" column="createtime" />
		<result property="note" column="note" />
	collection>
resultMap>


<select id="queryUserOrder" resultMap="userOrderResultMap">
	SELECT
	u.id,
	u.username,
	u.birthday,
	u.sex,
	u.address,
	o.id oid,
	o.number,
	o.createtime,
	o.note
	FROM
	`user` u
	LEFT JOIN `order` o ON u.id = o.user_id
select>

动态Sql四大标签

UserMapper.xml


<select id="queryUserByWhere" parameterType="user" resultType="user">
	SELECT id, username, birthday, sex, address FROM `user`
	WHERE 1=1
	<if test="sex != null and sex != ''">
		AND sex = #{sex}
	if>
	<if test="username != null and username != ''">
		AND username LIKE
		'%${username}%'
	if>
select>

UserMapper.xml


<select id="queryUserByWhere" parameterType="user" resultType="user">
	SELECT id, username, birthday, sex, address FROM `user`

	<where>
		<if test="sex != null">
			AND sex = #{sex}
		if>
		<if test="username != null and username != ''">
			AND username LIKE
			'%${username}%'
		if>
	where>
select>

UserMapper.xml


<select id="queryUserByWhere" parameterType="user" resultType="user">
	
	
	SELECT <include refid="userFields" /> FROM `user`
	
	<where>
		<if test="sex != null">
			AND sex = #{sex}
		if>
		<if test="username != null and username != ''">
			AND username LIKE
			'%${username}%'
		if>
	where>
select>


<sql id="userFields">
	id, username, birthday, sex, address
sql>

UserMapper.xml


<select id="queryUserByIds" parameterType="queryVo" resultType="user">
	SELECT * FROM `user`
	<where>
		
		
		
		
		
		
		<foreach collection="ids" item="item" open="id IN (" close=")"
			separator=",">
			#{item}
		foreach>
	where>
select>

测试程序和小结

@Test
	public void testMapper() throws Exception{
//		加载核心配置文件
		String resource="sqlMapConfig.xml";
		InputStream in = Resources.getResourceAsStream(resource);
//		创建SqlSessionFactory
		SqlSessionFactory build = new SqlSessionFactoryBuilder().build(in);
//		创建SqlSession
		SqlSession sqlSession = build.openSession();
		
//		SqlSession帮我生成实现类(给一个接口)
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		User user = userMapper.findUserById(10);
		System.out.println(user);
	}
  • selectOne和selectList

动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

  • namespace

mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

输入映射和输出映射

传递简单类型

使用#{}占位符,或者${}进行sql拼接。

传递pojo对象

Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。

传递pojo包装对象

  • QueryVo
public class QueryVo {
	// 包含其他的pojo
	private User user;

	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
}
  • Sql语句

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sjpql9mC-1589804296298)(C:\Users\dby\AppData\Roaming\Typora\typora-user-images\1577858257312.png)]

其他

useGeneratedKeyskeyProperty

在mybatis的配置文件中,有个叫keyProperty和useGeneratedKeys的属性。useGeneratedKeys 参数只针对 insert 语句生效,默认为 false。当设置为 true 时,表示如果插入的表以自增列为主键,则允许 JDBC 支持自动生成主键,并可将自动生成的主键返回。

useGeneratedKeys=”true” keyProperty=”对应的主键的对象”。

MyBatis在生成update语句时若使用if标签,如果前面的if没有执行,则可能导致有多余逗号的错误。

你可能感兴趣的:(SSM)