Mybatis 运作原理

在学习Mybatis原理之前我们先来看这样的jdbc代码 

@Test
	public void JdbcTest() {

		// 声明连接对象
		Connection conn = null;
		// 声明预处理对象
		PreparedStatement prep = null;
		// 声明结果集对象
		ResultSet result = null;

		try {
			// 加载数据库驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 创建数据库连接
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/mydb?charset=utf8&serverTimezone=UTC&useSSL=false", "root", "root");
			// 创建sql语句
			String sql = "select * from Celebrity where c_id=?";
			// 预处理Sql语句
			prep = conn.prepareStatement(sql);
			// 用过预处理对象,设置sql语句参数
			prep.setString(1, "10");
			// 执行sql语句返回结果集
			result = prep.executeQuery();
			// 处理结果集数据
			while (result.next()) {

				System.out.println(result.getString("c_id") + "   " + result.getString("c_name"));

			}

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			// 关闭结果集资源
			if (result != null) {
				try {
					result.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			// 关闭预处理对象资源
			if (prep != null) {
				try {
					prep.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			// 关闭连接对象资源
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}

		}

	}

在实际开发过程中我们很快就会发现原始JDBC的不足之处,

1.每次访问数据库都需要进行数据库连接对象的创建和关闭操作,占用了数据库连接的资源,影响了数据库的性能。
                   解决: 使用数据库连接池

2.数据库的操作语句使用了硬编码,导致(需求改变时)每次修改sql语句都需要重新编译java代码,不利于系统维护
                   解决:将sql语句抽取出来,形成一个xml配置文件,需求改变时,开发人员只需要专注于配置文件,不需要管java代码。
 

            3.数据库操作语句的设定参数使用了硬编码
                   解决:PreparedStatement将sql语句占位符和参数,配置在xml配置文件内

            4.结果集的处理存在硬编码,不利于维护
                   解决:将结果集(ResultSet)里面的数据直接和java对象映射在一起,这样就可以直接获取java对象

然后我们参考Mybatis的执行流程:

1. 配置MybatisConfig.配置文件,设置Mybatis环境配置DataSource数据源,配置ORM映射配置文件mapper.xml

2.加载MybatisConfig配置文件,创建SqlSessionFactory工厂对象

3.通过工厂对象factory创建sqlSession会话对象

4.在sqlSession会话对象方法内部 通过Configuration配置对象创建MappedStatement对象

          MappedStatement ms = configuration.getMappedStatement(statement);根据key(namespace+tagId)获取MappedStatement对象。

          MappedStatement会创建一个Cache对象,并指定唯一的key(由sql,mappedStatement,parameter,rowbound(用于分页)联合生成,具有唯一性),用于缓存数据库操作(涉及mybatis相关的一级缓存操作),当下次执行相同的操作时,通过检查Cache对象的key,如果key相同则表明是相同的数据库操作,则直接拿Cache里面的结果返回

5.通过内置的executer执行数据库相关操作

executer.query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)

           获取Cache,Cache为空,通过BaseExecutor执行数据库操作,

           Cache不为空,存在缓存,通过CachingExecutor获取结果(从缓存中拿取)

补充,#{}与${}的区别:
                       1.#{}表示占位符
                       2.${}表示拼接sql串,将接收到的参数不加如何修饰直接拼接到sql语句中
                                注意:但是这样也存在风险,可能引发sql注入(不建议使用)。
                                ${}只能使用value参数名来接收输入参数
(java简单类型),例子:select * from user where u_name like '%${value}%'

Mybatis完成增删改查操作(非注解)

       1.查询(通过主键查询)
         <!--标签的id属性起到标识标签的作用,同时由于mybatis框架会将sql语句封装到一个MappedStatement底层对象中,此id也就相当于MappedStatement对象的id -->
         <!--1.将SQL语句侧参数通过占位符(#{})提交到动态提交到sql语句中 -->
         <!--#{}表示一个占位符 -->
         <!--2.将sql语句的返回结果和java实体对象映射 -->
         <!--3.parameterType:表示sql语句输入参数的类型,注意如果参数为简单类型,则占位符参数名可以任意定义 -->
         <!--4.resultType:表示sql语句执行结果所映射的java对象的类型 (单条记录) -->
         <select id="getById" parameterType="int"
             resultType="com.ncs.entity.Celebrity">
             select * from celebrity where c_id=#{value}
         </select>
      
       2.查询(非主键模糊查询)
         <!--注意:resultType:指定的就是单条记录所映射的java对象 -->
         <!--${}表示拼接sql语句,将接收到的参数不加任何修饰直接拼接到sql语句中 -->
         <!--注意:但是这样存在sql注入风险 ,而且当使用${}拼接sql时,只能通过参数名value来接收参数,其他参数名定义不行。 -->
         <select id="getByName" parameterType="string"
             statementType="STATEMENT" resultType="com.ncs.entity.Celebrity">
             select * from celebrity where
             c_name like '%${value}%'
         </select>
      
      3.添加(mysql自增长主键)  //由于底层conn.setAutoCommit(false)设置为非自动提交,涉及数据一致性,所以用户必须手动提交来保证数据一致性。
         <!--mysql自增主键 -->
         <insert id="insertCelebrity"
             parameterType="com.ncs.entity.Celebrity">
             <!--如果使用自增长的主键,且需要返回自增长的主键属性值给到原来保存成功的对象上 -->
             <selectKey keyProperty="c_id" order="AFTER" resultType="java.lang.Integer">
                 select LAST_INSERT_ID()
             </selectKey>

             insert into celebrity(c_id,c_name) values(#{c_id},#{c_name})
         </insert>
      
      4.添加(mysql非自增长主键(uuid))
         <!--mysql非自增主键(uuid) -->
         <insert id="insertCelebrityWithUUID"
             parameterType="com.ncs.entity.Celebrity">
             <!--如果使用mysql uuid,且需要返回自增长的主键属性值给到原来保存成功的对象上 -->
             <selectKey keyProperty="c_id" order="BEFORE" resultType="java.lang.String">
                 select uuid()
             </selectKey>

             insert into celebrity(c_id,c_name) values(#{c_id},#{c_name})
         </insert>
      
      5.添加(Oracle非自增长(序列))
         <!--oracle非自增主键(sequence) -->
         <insert id="insertCelebrityWithSequence"
             parameterType="com.ncs.entity.Celebrity">
             <!--使用序列值,且需要返回自增长的主键属性值给到原来保存成功的对象上 -->
             <selectKey keyProperty="c_id" order="BEFORE" resultType="java.lang.String">
                 select SequenceName.nextval()
             </selectKey>

             insert into celebrity(c_id,c_name) values(#{c_id},#{c_name})
         </insert>
         
       6.删除 (由于底层conn.setAutoCommit(false)设置为非自动提交,涉及数据一致性,所以用户必须手动提交来保证数据一致性。)
         <!--由于mybatis底层conn.setAutoCommit(false),表示涉及数据一致性的操作需要用户手动提交 -->
         <delete id="deleteCelebrityById" parameterType="int">
             delete from celebrity where c_id=#{c_id}
         </delete>

       7.更新
         <!--由于mybatis底层conn.setAutoCommit(false),表示涉及数据一致性的操作需要用户手动提交 -->
         <update id="updateCelebrity" parameterType="com.ncs.entity.Celebrity">
            update celebrity set c_name=#{c_name} where c_id=#{c_id}
         </update>     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值