MyBatis(一) 概述与SQL定制、对象映射


个人博客网:https://wushaopei.github.io/    (你想要这里多有)

一、MyBatis概述

1、mybatis简介

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。

MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录.

2、mybatis历史

原是apache的一个开源项目iBatis, 2010年6月这个项目由apache software foundation 迁移到了google code,随着开发团队转投Google Code旗下,ibatis3.x正式更名为Mybatis ,代码于2013年11月迁移到Github(下载地址见后)。

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)

3、为什么要使用mybatis

MyBatis是一个半自动化的持久化层框架。

jdbc编程---当我们使用jdbc持久化的时候,sql语句被硬编码到java代码中。这样耦合度太高。代码不易于维护。在实际项目开发中会经常添加sql或者修改sql,这样我们就只能到java代码中去修改。

Hibernate和JPA

长难复杂SQL,对于Hibernate而言处理也不容易

内部自动生产的SQL,不容易做特殊优化。

基于全映射的全自动框架,javaBean存在大量字段时无法只映射部分字段。导致数据库性能下降。

对开发人员而言,核心sql还是需要自己优化

sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。

可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录。成为业务代码+底层数据库的媒介

4、理解 SqlSession及其子父类的含义!

SqlSession的使用范围

  • SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
  • SqlSession通过SqlSessionFactory创建。
  • SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

SqlSessionFactory

SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。

SqlSession

SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。
每个线程都应该它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

二、MyBatis的Hello示例程序

1、创建一个数据库和一个单表

drop database if exists mybatis;
create database mybatis;
use mybatis;
 ## 创建单表
####################################################################
create table t_user(
	`id` int primary key auto_increment,
	`last_name`	varchar(50),
	`sex` int
);

insert into t_user(`last_name`,`sex`) values('wsp168',1);

select * from t_user;

2、搭建mybatis开发环境

创建一个java工程

导 入 需 要 的 jar 包:

    log4j-1.2.17.jar
    mybatis-3.4.1.jar
    mysql-connector-java-5.1.7-bin.jar

3、创建Pojo对象User

不调用接口方法,直接映射到xml文件中!

package com.webcode.pojo;

public class User {
	
	private Integer id;
	private String lastName;
	private Integer sex;
	。。。。。。。。。。	
}

4、在src目录创建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>
  <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="root"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="com/webcode/pojo/UserMapper.xml"/>
  </mappers>
</configuration>

配置文件代码获取方法

5、创建UserMapper.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">
  <!-- 
  		namespace名称空间
  		取值一般有两种情况:
  			一种情况是:使用javaBean的全类名
  			二种情况是:使用Mapper接口的全类名
   -->
<mapper namespace="com.webcode.pojo.User">
	<!-- 
  	select标签用来配置一个select语句
  		id 用来配置一个唯一的标识
  		resultType 是查询完之后一条记录对应转换成为的javaBean对象
  		#{id}是占位符
   -->
  <select id="selectUserById" resultType="com.webcode.pojo.User">
    	select id,last_name lastName,sex from t_user where id = #{id}  
  </select>
</mapper>

 

6、传统mybatis的hello world 示例代码

 

package com.webcode.pojo.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.webcode.pojo.User;

public class UserTest {

	

	@Test
	public void testselectUserById() throws IOException {
		//从配置文件读取指定的资源,以输入流的形式返回
		InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
		
		// 通过sqlSessionFactoryBuilder创建SqlSessionFactory(从输入流获取连接条件,创建连接工厂)
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);		
		System.out.println(sqlSessionFactory);
		
		//从工厂中获取一个连接(看成是数据库连接池即可),相当于 以前的Connection对象,每次用来都用关闭
		SqlSession openSession = sqlSessionFactory.openSession();
		
		try {
			/*由相对路径映射到xml文件中的id,调动执行sql语句,
			并以resultType定义的类型返回到请求端或者是客户端*/
			User user = openSession.selectOne("com.webcode.pojo.User.selectUserById",1);
			System.out.println(user);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			openSession.close();//释放资源
		}
	}

}

 

打印结果:     User [id=1, lastName=wsp168, sex=1]

代码流程:

关于Mybatis的配置文件提示功能:

 

关于log4j的提示:

如果不想看到,解决方案为:

只要在应用的classpath中创建一个名称为log4j.properties的文件, 文件的具体内容如下:

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 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

注意:

7.加入log4j配置

导入‘log4j-1.2.17.jar’包

在工程下的config文件夹中创建 "log4j.properties"文件

\u4E0B\uFF1A 

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
# 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 [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@61832929
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1585787493.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5e853265]
DEBUG [main] - ==>  Preparing: select id,last_name lastName,sex from t_user where id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User [id=1, lastName=wsp168, sex=1]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5e853265]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5e853265]
DEBUG [main] - Returned connection 1585787493 to pool.

流程图解:

三、传统方式mybatis的增,删,改,查实现

1、UserDao:

package com.webcode.dao;

import java.util.List;

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

import com.webcode.pojo.User;
/**
 * @author 鮀城小帅
 * */
/**
 * 
 * 注意:在创建连接时,底层自动对事务commit做了false定义,而没有提交的事务会自动回滚。
 * 		在执行CRUD时要手动提交事务,即,在执行语句后,session.commit();
 * */
public class UserDao {

	
	private SqlSessionFactory sqlSessionFactory;
	
	
	/*
	 * 创建sql会话工厂方法
	 * */
	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
		
		this.sqlSessionFactory = sqlSessionFactory;
	}
	/*
	 * 根据id查询用户
	 * */
	public User queryUserById(Integer id) {
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			return openSession.selectOne("com.webcode.pojo.User.selectUserById",id);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			openSession.close();//释放资源
		}
		return null;
	}
	/*
	 * 查询所有用户
	 * */
	public List<User> queryUsers(){
		SqlSession session = sqlSessionFactory.openSession();

		try {
			return session.selectList("com.webcode.pojo.User.queryUsers");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();//释放资源
		}
		return null;
	}
	/*
	 * 添加用户
	 * */
	public int saveUser(User user) {
		SqlSession session = sqlSessionFactory.openSession();
		try {
			 int result = session.insert("com.webcode.pojo.User.saveUser",user);
			session.commit();//提交事务
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();//释放资源
		}
		return -1;
	}
	/*
	 * 根据id删除用户
	 * */
	public int deleteUserById(Integer id) {
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			int delete = openSession.delete("com.webcode.pojo.User.deleteUserById",id);
			openSession.commit();//手动提交事务
			return delete;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			openSession.close();//释放资源
		}
		
		return -1;
		
	}
	/*
	 * 修改用户
	 * */
	public int updateUser(User user) {
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			int update = openSession.update("com.webcode.pojo.User.updateUsers",user);
			openSession.commit();//手动提交事务
			return update;
		} catch (Exception e) {
			// TODO: handle exception
		}finally {
			openSession.close();//释放资源
		}
		return -1;
	}
	
}

2、编写UserMapper.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">
  <!-- 
  		namespace名称空间
  		取值一般有两种情况:
  			一种情况是:使用javaBean的全类名
  			二种情况是:使用Mapper接口的全类名
   -->
<mapper namespace="com.webcode.pojo.User">
	<!-- 
  	select标签用来配置一个select语句
  		id 用来配置一个唯一的标识
  		resultType 是查询完之后一条记录对应转换成为的javaBean对象
  		#{id}是占位符
   -->
  <select id="selectUserById" resultType="com.webcode.pojo.User">
  
    	select id,last_name lastName,sex from t_user where id = #{id}  
  </select>
  
  <!-- 查询全部的User对象 -->
  <select id="queryUsers" resultType="com.webcode.pojo.User">
  		select id,last_name lastName,sex from t_user
  </select>
  
   	<!-- parameterTypr参数类型(可选)
   		useGeneratedKeys="true"		使用(或返回)数据库生成的主键
		keyProperty="id"	把数据库返回的主键值注入到bean对象的id属性中
   	
   	 -->
  <insert id="saveUser" parameterType="com.webcode.pojo.User" >
  		<!-- 
  			selectKey标签可以定义一些查询语句,这些语句可以选择性地在大标签的sql语句之前或之后执行
  				我们希望,通过执行一个查询,把最后一次生成的id返回。
  					order属性配置执行的顺序
  						BEFORE		之前
  						AFTER		之后
  					keyProperty="id"	把数据库返回的主键值注入到bean对象的id属性中
  					resultType="int"	设置selectKey查询之后返回的类型是什么 int 表示Integer类型
  		 -->
  		 <selectKey order="AFTER" keyProperty="id" resultType="int">
  		 		select last_insert_id()
  		 </selectKey>
  		insert into t_user (`last_name`,`sex`) values(#{lastName},#{sex}) 
  		
  </insert>
<!--   <insert id="saveUser" parameterType="com.webcode.pojo.User"  -->
<!--   	useGeneratedKeys="true" keyProperty="id"> -->
<!--   		insert into t_user (`last_name`,`sex`) values(#{lastName},#{sex})  -->
<!--   </insert> -->
  
  	<!-- 根据id删除一个用户 -->
  <delete id="deleteUserById" parameterType="int">
  	delete from t_user where id=#{id}  	
  </delete>
  
  <update id="updateUser" parameterType="com.webcode.pojo.User">
  	update t_user set last_name = #{lastName},sex=#{sex} where id=#{id}
  </update>
  
</mapper>

映射关系图解:

3、编写UserDao测试

package com.webcode.dao.test;

import static org.junit.Assert.*;

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

import com.webcode.dao.UserDao;
import com.webcode.pojo.User;
/**
 * @author 鮀城小帅
 * */
public class UserDaoTest {
	
	private static UserDao userDao;
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
				.build(Resources.getResourceAsStream("mybatis-config.xml"));
		userDao = new UserDao();
		userDao.setSqlSessionFactory(sqlSessionFactory);
	}

	@Test
	public void testQueryUserById() {
		System.out.println(userDao.queryUserById(1));
	}

	@Test
	public void testQueryUsers() {
		userDao.queryUsers().forEach(System.out::println);
	}

	@Test
	public void testSaveUser() {
		userDao.saveUser(new User(null, "xxx", 1));
	}

	@Test
	public void testDeleteUserById() {
		userDao.deleteUserById(3);
	}

	@Test
	public void testUpdateUser() {

		userDao.updateUser(new User(3,"aaa",0));
	}

}

4、插入记录并返回主键

打印结果:

5、插入记录并返回主键

  <!-- parameterType类型(可选) -->
  <insert id="saveUser" parameterType="com.webcode.pojo.User" keyProperty="id"        useGeneratedKeys="true" >
  		<!--   parameterType 参数类型(可选)
			useGeneratedKeys="true"		使用(或返回)数据库生成的主键
			keyProperty="id"	把数据库返回的主键值注入到bean对象的id属性中
	 -->
  		insert into t_user(`last_name`,`sex`) values(#{lastName},#{sex})
  </insert>

6、标签的使用

<!-- parameterType类型(可选) -->
  <insert id="saveUser" parameterType="com.webcode.pojo.User"  >
  		
  		<!-- 
  			selectKey标签可以定义一些查询语句,这些语句可以选择性地在大标签的sql语句之前或之后执行
  				我们希望,通过执行一个查询,把最后一次生成的id返回。
  					order属性配置执行的顺序
  						BEFORE		之前
  						AFTER		之后
  					keyProperty="id"	把数据库返回的主键值注入到bean对象的id属性中
  					resultType="int"	设置selectKey查询之后返回的类型是什么 int 表示Integer类型
  		 -->
  		 <selectKey order="AFTER" keyProperty="id" resultType="int"> 
   		 	select last_insert_id 
   		 </selectKey> 
  		insert into t_user(`last_name`,`sex`) values(#{lastName},#{sex})
  </insert>

四、Mapper 接口方式的 mybatis 的增,删,改,查实现

1、Mapper 接口编程的命名习惯

  1. JavaBean对象是                User
  2. Mapper接口的名称是:         UserMapper
  3. sql语句的配置文件命名:       UserMapper.xml
  1. JavaBean对象是                Book
  2. Mapper接口的名称是:         BookMapper
  3. sql语句的配置文件命名:       BookMapper.xml

2、Mapper接口开发有四个开发规范 必须遵守

1、名称空间必须是接口的全类名
2、方法名必须与id值一致
3、parameterType必须与方法参数类型一致
4、resultType必须与方法返回值一致(是指javaBean对象)

3、编写 Mapper 接口

public interface UserMapper {

	public User queryUserById(Integer id);

	public List<User> queryUsers();

	public int saveUser(User user);

	public int deleteUserById(Integer id);

	public int updateUser(User user);
	
}

4、UserMapper.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名称空间值必须是Mapper接口的全类名
   -->
<mapper namespace="com.webcode.mapper.UserMapper">
<!-- 	
		Mapper接口方案需要注意的第二点事项是:
			方法名,必须要和id值一致
		Mapper接口方案需要注意的第三点事项是:
			返回值类型必须一致
		Mapper接口方案需要注意的第四点事项是:
			参数类型也必须一致(写就必须一致)
 -->
	<select id="queryUserById" resultType="com.webcode.pojo.User" parameterType="int">
		select id,last_name lastName,sex from t_user where id = #{id}
	</select>
<!-- 	public List<User> queryUsers(); -->
	<select id="queryUsers" resultType="com.webcode.pojo.User">
		select id,last_name lastName,sex from t_user
	</select>

<!-- 	public int saveUser(User user);
			普通类型可以忽略(主要是javaBean对象)
 -->
	<insert id="saveUser" parameterType="com.webcode.pojo.User" useGeneratedKeys="true" keyProperty="id">
		insert into t_user(last_name,sex) values(#{lastName},#{sex})
	</insert>

<!-- 	public int deleteUserById(Integer id); -->
	<delete id="deleteUserById">
		delete from t_user where id = #{id}
	</delete>
<!-- 	public int updateUser(User user); -->
  	<update id="updateUser" parameterType="com.webcode.pojo.User">
  		update t_user set last_name = #{lastName},sex = #{sex} where id = #{id}
  	</update>
</mapper>

5、编写UserMapper测试

package com.webcode.mapper.test;



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 com.webcode.mapper.UserMapper;
import com.webcode.pojo.User;

import org.junit.BeforeClass;
import org.junit.Test;

public class UserMapperTest {
	static SqlSessionFactory sqlSessionFactory;
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
			 sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
	}

	@Test
	public void testQueryUserById() {
		SqlSession session = sqlSessionFactory.openSession();
		try {
			UserMapper mapper = session.getMapper(UserMapper.class);
			System.out.println(mapper.queryUserById(1));
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			session.close();
		}
	}

	@Test
	public void testQueryUsers() {
		SqlSession session = sqlSessionFactory.openSession();
		try {
			UserMapper mapper = session.getMapper(UserMapper.class);
			mapper.queryUsers().forEach(System.out::println);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			session.close();
		}
	}

	@Test
	public void testSaveUser() {
		SqlSession session = sqlSessionFactory.openSession();
		try {
			UserMapper mapper = session.getMapper(UserMapper.class);
			int saveUser = mapper.saveUser(new User(null,"吴",11));
			session.commit();
			System.out.println(saveUser);
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			session.close();
		}
	}

	@Test
	public void testDeleteUserById() {
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			UserMapper mapper = openSession.getMapper(UserMapper.class);
			int deleteUserById = mapper.deleteUserById(2);
			openSession.commit();
			System.out.println(deleteUserById);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			openSession.close();
		}
	}

	@Test
	public void testUpdateUser() {
		SqlSession session = sqlSessionFactory.openSession();
		try {
			UserMapper mapper = session.getMapper(UserMapper.class);
			int updateUser = mapper.updateUser(new User(1,"少",33));
			session.commit();
			System.out.println(updateUser);
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			session.close();
		}
	}

}

五、mybatis的核心配置之properties

	<!-- 
		properties标签可以用来定义多组键值对
			每个property标签是一组键值对 
		properties标签还可以引入单独的属性配置文件
			resource="jdbc.properties" 引入classpath路径下的jdbc.properties配置文件
		源码目录,就是classPath路径
		
		properties标签在引入外部属性配置文件和内部定义属性的时候。外部会替换掉内部定义的值。
	-->
	<properties resource="jdbc.properties">
		<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
		<property name="username" value="root"/>
	</properties>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值