• MyBatis基础-1


    1.Mybatis简介
    2.Mybatis环境搭建
    3.Mybatis的开发方式
    

    一.什么框架

    框架其本质是半成品程序,提供相关规范,并且提供大量可重用的组件。
    目的:让开发者开发出结构比较良好,可读性较强,扩展性和可维护性较好的工程。
    
    第三阶段常见的框架:Mybatis,hibernate,spring,springmvc,struts2,webservice,activiti...
    

    二.Mybatis简介

    1.简介
    1.MyBatis Apache基金会下的开源框架,是持久层框架(Data Access Objects:DAO),对JDBC轻量级的封装,前身为IBatis.
    
    2.下载
    https://github.com/mybatis/mybatis-3/releases
    
    3.Mybatis特点
    1.简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易
    于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
    2.灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优
    化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
    3.解除sql与程序代码的耦合:通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易
    维护,更易单元测试。sql和代码的分离,提高了可维护性。
    4.提供映射标签,支持对象与数据库的orm字段关系映射
    5.提供对象关系映射标签,支持对象关系组建维护
    6.提供xml标签,支持编写动态sql
    
    4.功能架构

    Mybatis的功能架构分为三层:
    1.API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求
    就会调用数据处理层来完成具体的数据处理。
    2.数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的
    请求完成一次数据库操作。
    3.基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东
    西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
    
    5.执行流程及原理
    总体执行流程:
    1. 加载配置并初始化
    加载配置文件,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语
    句、结果映射配置),存储在内存中。
    2. 接收调用请求
    调用Mybatis提供的API(SqlSession的CURD操作),传入Sql的相应ID和参数对象,将请求传递给下层的请求处理层进
    行处理。
    3.处理相应的操作请求
    (A)根据SQL的ID查找对应的MappedStatement对象。
    (B)根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。
    (C)获取数据库连接,根据得到的最终SQL语句和传入参数到数据库执行,并得到执行结果。
    (D)根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
    (E)释放连接资源
    

    三.Mybatis开发环境搭建

    1.开发步骤
    1.配置sqlMapConfig.xml(习惯命名mybatis-config.xml)
    	配置数据库连接信息
    2.使用SqlSessionFactoryBulider解析sqlMapConfig.xml文件,获取会话对像SqlSession对像
    3.编写Dao代码并配置Mapper.xml文件
    	该Mapper.xml用来编写sql语句,并对数据库表和Java对像,字段和Java对像属性建立映射关系。
    4.使用SqlSession中的API进行CURD操作即可。
    

    步骤一:新建Maven工程

    步骤二:在pom.xml文件中引入jar包依赖

    <dependencies>
        	<!--mybatis-->
    		<dependency>
    			<groupId>org.mybatis</groupId>
    			<artifactId>mybatis</artifactId>
    			<version>3.4.6</version>
    		</dependency>
    		<!--mysql-->
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    			<version>5.1.40</version>
    		</dependency>
    		<!--log4j-->
    		<dependency>
    			<groupId>log4j</groupId>
    			<artifactId>log4j</artifactId>
    			<version>1.2.17</version>
    		</dependency>
    
    	</dependencies>
    

    步骤三:在resources目录下,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>
    	<!-- 读取数据库连接信息 -->
    	<properties resource="db.properties"></properties>
    	<!-- 数据连接环境 -->
    	<environments default="development">
    		<environment id="development">
    			<!-- 使用JDBC事务进行事务管理 -->
    			<transactionManager type="JDBC" />
    			<!-- 数据源配置:POOLED表示使用连接池来管理连接对像 -->
    			<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>
    	<!-- 加载mapper文件 -->
    	<mappers>
    		<mapper resource="dao/UserMapper.xml"/>
    	</mappers>
    </configuration>
    

    log4j.properties日志文件:

    # Global logging configuration
    log4j.rootLogger=DEBUG, 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
    

    db.properties数据库连接

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql:///javaee
    jdbc.username=root
    jdbc.password=tiger
    

    步骤四:在dao层创建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">
    <!--namespace表示命名空间,用来标识该Mapper文件-->
    <mapper namespace="dao.UserMapper">
    	
        <!--id为该Sql语句的唯一标识,resultType表示查询出的结果要封装成的java类型-->
    	<select id="selectAll" resultType="model.User">
    		select * from USER
    	</select>
    </mapper>
    

    步骤五:使用mybatis的API进行CRUD操作

    public class MyBatisSession {
    
    	public static void main(String[] args) throws IOException {
    		//1.解析mybatis-config.xml文件
    		String resource = "mybatis-config.xml";
    		
    		//2.获取输入流
    		InputStream inputStream = Resources.getResourceAsStream(resource);
    		
    		//3.SqlSessionFactory工厂
    		SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);
    		
    		//4.创建sqlSession
    		SqlSession session = sqlSessionFactory.openSession();
    		
    		//namespace.sqlId=statementId
    		List<User> list = session.selectList("dao.UserMapper.selectAll");
    		for(User user:list){
    		System.out.println(user.getId()+","+user.getUsername()+","+user.getPassword());
    		}
    		//5.关闭资源
    		session.close();
    		
    	}
    
    }
    

    四.Mybatis相关类的生命周期

    1.SqlSessionFactoryBuilder
    这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此
    SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。你可以重用
    SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的
    XML 解析资源开放给更重要的事情
    
    2.SqlSessionFactory
    SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用
    SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代
    码“坏味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是应用作用域。有很多方法可以做到,最简单的
    就是使用单例模式或者静态单例模式。
    
    3.SqlSession
    每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的
    最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量
    也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理作用域中,比如 Servlet 架构中的
    HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域
    中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很
    重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭
    

    五.Mybatis工具类

    
    public class MybatisUtil {
    
    	static SqlSessionFactory sqlSessionFactory;
    
    	static {
    		
    		String resource = "mybatis-config.xml";
    		InputStream inputStream;
    		try {
    			inputStream = Resources.getResourceAsStream(resource);
    			sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		
    	}
    	
    	/**
    	 * 该方法调用必须在应用程序的成员方法中调用
    	 * @return
    	 */
    	public static SqlSession findSqlSession(){
    		
    		return sqlSessionFactory.openSession();
    	}
    }
    
    

    六.Mybatis的开发方式(Mybatis与数据库交互方式)

    1.传统方式进行CRUD操作
    通过调用MyBatis中SqlSession对象的方法从而达到与数据库交互的方式,有一些类似DBUtils的操作!
    下面是使用MyBatis的方法,是创建一个和数据库打交道的SqlSession对象,然后根据StatementId 和参数来操作
    数据库。如图所示 :
    

    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="dao.UserMapper">
    	
    
    	<select id="selectAll" resultType="model.User">
    		select * from USER
    	</select>
    	
    	<!-- OGNL表达式 
    		1.简单类型参数,#{}中参数的命名可以自定义
    		2.POJO参数,#{}中参数的命名必须是POJO对像中get方法的后缀(首字母小写)一致。
    	-->
    	<select id="selectById" resultType="model.User">
    		select * from USER where id = #{id}
    	</select>
    	
    	<select id="selectByItem" resultType="model.User" parameterType="model.User">
    		select * from USER where username=#{username} and password=#{password}
    	</select>
    	
    	<insert id="insert" parameterType="model.User">
    		insert into USER(username,password) values(#{username},#{password})
    	</insert>
    	
    	<delete id="delete" parameterType="model.User">
    		delete from USER where id = #{id}
    	</delete>
    	
    	<update id="update" parameterType="model.User">
    		update USER set username=#{username},password=#{password} where id = #{id}
    	</update>
    </mapper>
    

    dao层代码

    public class UserDao {
    
    	public void insert(User user) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    		try {
    			session.insert("dao.UserMapper.insert", user);
    
    			// 提交事务
    			session.commit();
    		} catch (Exception e) {
    			e.printStackTrace();
    			session.rollback();
    		} finally {
    			session.close();
    		}
    
    	}
    
    	public void delete(User user) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    		try {
    			session.delete("dao.UserMapper.delete", user);
    
    			// 提交事务
    			session.commit();
    		} catch (Exception e) {
    			e.printStackTrace();
    			session.rollback();
    		} finally {
    			session.close();
    		}
    	}
    
    	public void update(User user) {
    		SqlSession session = MybatisUtil.findSqlSession();
    		try {
    			session.update("dao.UserMapper.update", user);
    
    			// 提交事务
    			session.commit();
    		} catch (Exception e) {
    			e.printStackTrace();
    			session.rollback();
    		} finally {
    			session.close();
    		}
    	}
    
    	public User selectById(int id) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    
    		User user = null;
    
    		try {
    			user = session.selectOne("dao.UserMapper.selectById", id);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			session.close();
    		}
    		return user;
    	}
    
    	public List<User> selectAll() {
    		
    		SqlSession session = MybatisUtil.findSqlSession();
    
    		List<User> users = null;
    
    		try {
    			users = session.selectList("dao.UserMapper.selectAll");
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			session.close();
    		}
    		return users;
    	}
    
    	public User selectByItem(User user) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    		try {
    			user = session.selectOne("dao.UserMapper.selectByItem", user);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			session.close();
    		}
    		return user;
    	}
    
    }
    
    

    service层代码

    public class UserService {
    
    	UserDao dao = new UserDao();
    
    	public void save(User user) {
    
    		dao.insert(user);
    
    	}
    
    	public void remove(User user) {
    
    		dao.delete(user);
    	}
    
    	public void modify(User user) {
    		dao.update(user);
    	}
    
    	public User findById(int id) {
    		return dao.selectById(id);
    	}
    
    	public List<User> findAll() {
    		return dao.selectAll();
    	}
    
    	public User findByItem(User user) {
    
    		return dao.selectByItem(user);
    	}
    }
    

    单元测试类

    public class CRUDTest {
    	
    	UserService ser;
    
    	@Before
    	public void init(){
    		
    		ser = new UserService();
    	}
    	
    	@Test
    	public void testSave(){
    		
    		User user = new User();
    		user.setUsername("张三");
    		user.setPassword("1234");
    		ser.save(user);
    	}
    	
    	@Test
    	public void testModify(){
    		
    		User user = new User();
    		user.setId(3);
    		//user.setUsername("张三");
    		user.setPassword("0000");
    		ser.modify(user);
    	}
    	
    	@Test
    	public void testRemove(){
    		
    		User user = new User();
    		user.setId(3);
    		
    		ser.remove(user);
    	}
    	
    	@Test
    	public void testFindById(){
    		
    		User user = ser.findById(1);
    		
    		System.out.println(user.getId()+","+user.getUsername());
    	}
    	
    	@Test
    	public void testFindByItem(){
    		
    		User user = new User();
    		user.setUsername("admin");
    		user.setPassword("admin");
    		User findUser = ser.findByItem(user);
    		System.out.println(findUser.getId()+","+findUser.getUsername()+","+findUser.getPassword());
    	}
    	
    	
    }
    
    2.面向接口方式编程

    原理

    MyBatis将核心配置文件中的每一个节点抽象为一个 Mapper 接口,而这个接口中声明的方法和跟节点中的
    <select|update|delete|insert>节点项对应,即<select|update|delete|insert> 节点的id值为Mapper接口中的
    方法名称,parameterType值表示Mapper对应方法的入参类型,而resultMap 值则对应了Mapper接口表示的返
    回值类型或者返回结果集的元素类型。
    根据MyBatis的配置规范配置好后,通过SqlSession.getMapper(XXXMapper.class) 方法,MyBatis会根据相应的
    接口声明的方法信息,通过动态代理机制生成一个Mapper实例,我们使用Mapper接口的某一个方法时,MyBatis会根据
    这个方法的方法名和参数类型,确定Statement Id,底层还是通过
    SqlSession.select("statementId",parameterObject);
    或者
    SqlSession.update("statementId",parameterObject);
    等等来实现对数据库的操作,
    MyBatis引用Mapper接口这种调用方式,纯粹是为了满足面向接口编程的需要。(其实还有一个原因是在于,面
    向接口的编程,使得用户在接口上可以使用注解来配置SQL语句,这样就可以脱离XML配置文件,实现“0配置”)
    

    开发规范

    面向接口编程,必须遵守一定开发规范,如下:
    1.接口和mapper必须同包放置
    2.接口的类名必须和mapper的名称一致
    3.接口方法名称必须和mapper中Sql的Id一致
    4.mapper文件的namespace必须和接口的完全限定名一致
    5.mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
    6.mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致。
    7.接口中方法不允许重载。
    8.如果传入多个参数,请把参数封装到POJO或Map集合中(也可以使用注解方式).
    

    mapper接口

    public interface UserMapper {
    
    	public void insert(User user);
    	
    	public void delete(User user);
    	
    	public void update(User user);
    	
    	public User selectById(User user);
    	
    	public List<User> selectAll();
    	
        //注解方式支持多参传入
    	public List<User> selectByPage(@Param(value="firstIndex")int firstIndex,@Param(value="maxResult")int maxResult);
    	
        //????
    	public List<User> selectByPage2(int firstIndex,int maxResult);
        
        //多参传值时,一般封装成map或POJO进行处理
        public List<User> selectByPage3(Map<String,Integer> map);
        
        public List<User> selectByLike(User user);
    	
    }
    

    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="crud2.mapper.UserMapper">
    	
    
    	<select id="selectAll" resultType="model.User">
    		select * from USER
    	</select>
    	
    	<!-- OGNL表达式 
    		1.简单类型参数,#{}中参数的命名可以自定义
    		2.POJO参数,#{}中参数的命名必须是POJO对像中get方法的后缀(首字母小写)一致。
    	-->
    	<select id="selectById" resultType="model.User" parameterType="model.User">
    		select * from USER where id = #{id}
    	</select>
    	<!--多参传值时,#{}中参数名和接口中@Param()中的值一致-->
    	<select id="selectByPage" resultType="model.User">
    		select * from USER limit #{firstIndex},#{maxResult}
    	</select> 
    	
        <!--????-->
    	<select id="selectByPage2" resultType="model.User">
    		select * from USER limit #{0},#{1}
    	</select> 
        
        <!--接收参数为map类型-->
        <select id="selectByPage3" resultType="model.User"  parameterType="java.util.Map">
    		select * from USER limit #{firstIndex},#{maxResult}
    	</select> 
       
        <!--不要使用EL${}取值,使用函数处理-->
        <select id="selectByLike" resultType="model.User"  parameterType="model.User">
    		select * from USER where username like concat('%',#{username},'%');
    	</select> 
    	
    	
    	<insert id="insert" parameterType="model.User">
    		insert into USER(username,password) values(#{username},#{password})
    	</insert>
    	
    	<delete id="delete" parameterType="model.User">
    		delete from USER where id = #{id}
    	</delete>
    	
    	<update id="update" parameterType="model.User">
    		update USER set username=#{username},password=#{password} where id = #{id}
    	</update>
    	
    	
    </mapper>
    

    service代码

    public class UserService implements IUserService {
    
    	@Override
    	public void save(User user) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    		// 代理对像
    		UserMapper mapper = session.getMapper(UserMapper.class);
    		try {
    			mapper.insert(user);
    			session.commit();
    		} catch (Exception e) {
    			session.rollback();
    		} finally {
    			session.close();
    		}
    
    	}
    
    	@Override
    	public void remove(User user) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    		// 代理对像
    		UserMapper mapper = session.getMapper(UserMapper.class);
    		try {
    			mapper.delete(user);
    			session.commit();
    		} catch (Exception e) {
    			session.rollback();
    		} finally {
    			session.close();
    		}
    
    	}
    
    	@Override
    	public void modify(User user) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    		// 代理对像
    		UserMapper mapper = session.getMapper(UserMapper.class);
    		try {
    			mapper.update(user);
    			session.commit();
    		} catch (Exception e) {
    			session.rollback();
    		} finally {
    			session.close();
    		}
    
    	}
    
    	@Override
    	public User findById(User user) {
    		SqlSession session = MybatisUtil.findSqlSession();
    		// 代理对像
    		UserMapper mapper = session.getMapper(UserMapper.class);
    
    		return mapper.selectById(user);
    	}
    
    	@Override
    	public List<User> findAll() {
            
    		SqlSession session = MybatisUtil.findSqlSession();
    		// 代理对像
    		UserMapper mapper = session.getMapper(UserMapper.class);
            
            List<User> list = mapper.selectAll();
            
           	session.close();
    
    		return list;
    	}
    
    	@Override
    	public List<User> findByPage(int firstIndex,int maxResult) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    		// 代理对像
    		UserMapper mapper = session.getMapper(UserMapper.class);
            
           	List<User>  list = mapper.selectByPage(firstIndex,maxResult);
            
            session.close();
            
    		return list;
    	}
    	
    	@Override
    	public List<User> findByPage2(int firstIndex,int maxResult) {
    
    		SqlSession session = MybatisUtil.findSqlSession();
    		// 代理对像
    		UserMapper mapper = session.getMapper(UserMapper.class);
            
            session.close();
            
    		return mapper.selectByPage2(firstIndex,maxResult);
    	}
    
    }
    
    
  • 相关阅读:
    高级映射之事务
    配置tomcat-users.xml文件
    动态SQL之标签
    性能测试
    Service
    添加 aar 或 jar 包依赖 的方式
    安卓设备 以太网代理 问题排查
    剑指offer:面试题15、链表中倒数第 K 个结点
    剑指offer:面试题14、调整数组顺序使奇数位于偶数前面
    剑指offer:面试题13、在O(1)时间删除链表结点
  • 原文地址:https://www.cnblogs.com/zongJianKun/p/zongJianKun.html
Copyright © 2020-2023  润新知