MyBatis介绍 运行原理和增删改查

1.1.什么是框架

框架(framework)(Framework)是一个框子——指其约束性,也是一个架子——指其支撑性,即已经对基础的代码进行了封装并提供相应的API,开发者在使用框架是直接调用封装好的api可以省去很多代码编写,从而提高工作效率和开发速度。

如果将开发完成的软件比作是一套已经装修完毕的新房,那框架就好比是一套已经修建好的毛坯房。用户直接购买毛坯房,建筑质量和户型合理有保证,还省去了自己建造房屋的时间,一举多得。

1.2.框架要解决的问题

框架要解决的最重要的一个问题是技术整合的问题,在 J2EE 的 框架中,有着各种各样的技术,不同的 软件企业需要从 J2EE 中选择不同的技术,这就使得软件企业最终的应用依赖于这些技术,技术自身的复杂性和技 术的风险性将会直接对应用造成冲击。而应用是软件企业的核心,是竞争力的关键所在,因此应该将应用自身的设 计和具体的实现技术解耦。这样,软件企业的研发将集中在应用的设计上,而不是具体的技术实现,技术实现是应 用的底层支撑,它不应该直接对应用产生影响。

1.3.传统Jdbc代码问题分析

public class JdbcTest {
    public static void main(String[] args) {
        try {
            //1.加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.创建连接对象
            String url = "jdbc:mysql://192.168.10.137:3306/ssm";
            Connection connection = DriverManager.getConnection(url, 
                                                                "root",
                                                                "1111");
            String sql = "select * from account";
            //3.准备PreparedStatement对象
            PreparedStatement pst = connection.prepareStatement(sql);
            //4.执行sql语句
            ResultSet rs = pst.executeQuery();
            //5.遍历结果集
            while(rs.next()){
                Integer id = rs.getInt("id");
                String name = rs.getString("name");
                Double money = rs.getDouble("money");
                System.out.println(id + " " + name + " " + money);
            }
            //6.关闭资源
            rs.close();
            pst.close();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 问题

    1. 手动创建和释放链接

    2. sql语句在代码中硬编码

    3. 对结果的解析

1.4.MyBatis框

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、获取结果集等jdbc繁杂的过程代码。

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis。iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。

2.0.MyBatis运行原理

mybatis运行原理
		mybatis-config.xml
		mapper.xml mapper.xml mapper.xml			(--->代表从上面传下来的)
			|
			|
			|
		    Resources
			|
			|
			|
		 SqlSessionFactoryBuilder 会话工厂构建者
			|
			|--->Configuration(conn,Map<namespace+id, MappedStatement(sql,resultType)>)
			|
		   SqlSessionFactory  构建会话工厂
			|
			|--->Configuration(conn,Map<namespace+id, MappedStatement(sql,resultType)>)
			|
		    SqlSession  通过工厂类创建SqlSession对象
			|
			|--->Map<namespace+id , MappedStatement(sql, resultType)>, conn
			|
		     ProxyFactory 生成代理类
			|
			|--->mappedStatement(sql语句--附加操作,conn链接)
			| 
		      Executor  执行器
		   |     	| 
		   |     	|
		   |	    	|
		输入参数映射	输出结果映射

MyBatis框架在操作数据库时,大体经过了8个步骤:

1.读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。

2.加载映射文件:映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

3.构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。

4.创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法,是一个既可以发送sql执行并返回结果的,也可以获取mapper的接口

5.Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。

6.MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。

7.输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。

8.输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。

2.1.MyBatis的CRUD


2.1.1.单个参数绑定

    <!--
        parameterType:指定输入参数的类型
        resultType:指定数据结果封装的数据类型
		#{id}:它代表占位符,相当于原来 jdbc 部分所学的?,都是用于替换实际的数据。
    -->
    <select id="findUserById" parameterType="java.lang.Integer" 
            				  resultType="com.by.pojo.User" >
        select * from user where id=#{id}<!--只有一个参数时,#{任意书写}-->
    </select>
    @Test
    public void testFindUserById(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = userDao.findUserById(41);
        System.out.println(user);
    }

2.1.2.序号参数绑定

    //传递多个参数
    public User findUserByIdAndName(Integer id, String username);
     <select id="findUserByIdAndName" resultType="com.by.pojo.User" >
        SELECT * FROM user
        WHERE id = #{arg0} AND username = #{arg1} <!--arg0 arg1 arg2 ...-->
    </select>
    @Test
    public void testFindUserByIdAndName(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = userDao.findUserByIdAndName(41,"张三丰");
        System.out.println(user);
    }

2.1.3.注解参数绑定

    //传递多个参数
    public User findUserByIdAndName2(@Param("id")Integer id,
                                     @Param("username")String username);
    <select id="findUserByIdAndName2" resultType="com.by.pojo.User" >
        SELECT * FROM user
        WHERE id = #{id} AND username = #{username}
    </select>
    @Test
    public void testFindUserByIdAndName2(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = userDao.findUserByIdAndName2(41,"张三丰");
        System.out.println(user);
    }

2.1.4.对象参数绑定

    //使用对象属性进行参数绑定
    public User findUserByUserInfo(User user);
    <select id="findUserByUserInfo" parameterType="com.by.pojo.User" 
            									resultType="com.by.pojo.User">
        SELECT * FROM user
        WHERE id = #{id} AND username = #{username}<!--参数为对象时,#{属性名}-->
    </select>
    @Test
    public void testFindUserByName(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User userInfo = new User();
        userInfo.setId(41);
        userInfo.setUsername("张三丰");
        User user = userDao.findUserByUserInfo(userInfo);
        System.out.println(user);
    }

2.1.5.Map参数绑定

	//使用Map进行参数绑定
	public User findUserByMap(Map<String, Object> map);

    <select id="findUserByMap" 
            parameterMap="java.util.Map" resultType="com.by.pojo.User">
        SELECT * FROM user
        WHERE id = #{id} AND username = #{username}
    </select>
    @Test
    public void testFindUserByMap(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id",41);
        map.put("username","张三丰");
        User user = userDao.findUserByMap(map);
        System.out.println(user);
    }

4.1.6.模糊查询

    //模糊查询
    public  List<User> findUserByName(String username);
    <select id="findUserByName" parameterType="string" resultType="com.by.pojo.User">
        <!-- select * from user where username like concat('%',#{username},'%') -->
        select * from user where username like '%${value}%'<!--${}括号中只能是value-->
    </select>
   @Test
    public void testFindUserByName(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.findUserByName("张");
        for (User user : userList) {
            System.out.println(user);
        }
    }

2.1.7.sql注入

   //sql注入
    public User login(User user);
    <select id="login" parameterType="com.by.pojo.User" resultType="com.by.pojo.User">
        select * from user where username = '${username}' and password = '${password}'
    </select>
    @Test
    public void testLogin(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User userInfo = new User();
        userInfo.setUsername("张三丰' #");
        userInfo.setPassword("123");
        User user = userDao.login(userInfo);
        System.out.println(user);
    }

#{} 和${}的区别:

  • #{}符

    1. #{}表示一个占位符号 通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换

    2. #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类 型值,#{}括号中可以是 value 或其它名称。

    3. #{}可以有效防止 sql 注入。

  • ${}符

    1. ${}表示拼接 sql 串 通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换

    2. ${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value

2.1.8.聚合函数查询

//聚合函数查询
public Integer getTotal();
<!--聚合函数查询-->
<select id="getTotal" resultType="int">
    SELECT COUNT(id) FROM user
</select>
@Test
public void testGetTotal(){
    Integer total = userDao.getTotal();
    System.out.println(total);
}

2.2.删除

    //删除
    public void deleteUserById(Integer id);
    <delete id="deleteUserById" parameterType="Integer">
        DELETE FROM user
        WHERE id = #{id}
    </delete>
 @Test
    public void testDeleteUserById(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        userDao.deleteUserById(41);
        sqlSession.commit();
    }

2.3.修改

  //修改
    public void updateUserById(User user);
    <update id="updateUserById" parameterType="com.by.pojo.User">
        update user set username=#{username},password=#{password},
        birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
    </update>
    @Test
    public void testUpdateUserById(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = new User();
        user.setUsername("马德华");
        user.setPassword("111");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("高老庄");
        user.setId(42);
        userDao.updateUserById(user);
        sqlSession.commit();
    }

2.3.添加

    //添加
    public void insertUser(User user);
<insert id="insertUser" parameterType="com.by.pojo.User">
        <!--
            主键回填:新增之后,获取新增记录的id值
            keyProperty="id":主键对应实体类的属性
            order="AFTER":先执行插入语句,之后再执行查询语句
            resultType="java.lang.Integer":主键的数据类型
        -->
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            /*查询出刚刚插入的记录自增长id*/
            select last_insert_id();
        </selectKey>
        insert into user(username,password,birthday,sex,address)
        values(#{username},#{password},#{birthday},#{sex},#{address});
</insert>

或者

	<!--
        useGeneratedKeys=“true”:获取数据库生成的主键
        keyProperty=“id”:主键对应实体类的属性
    -->
    <insert id="insertUser" useGeneratedKeys="true" 
            keyProperty="id" parameterType="com.by.pojo.User">
        <!--
            主键回填:新增之后,获取新增记录的id值
            keyProperty="id":主键对应实体类的属性
            order="AFTER":先执行插入语句,之后再执行查询语句
            resultType="java.lang.Integer":主键的数据类型

            <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
                /*查询出刚刚插入的记录自增长id*/
                select last_insert_id();
            </selectKey>
         -->
        insert into user(username,password,birthday,sex,address)
        values(#{username},#{password},#{birthday},#{sex},#{address});
    </insert>

    @Test
    public void testInsertUser(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = new User();
        user.setUsername("刘德华");
        user.setPassword("111");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("香港");
        userDao.insertUser(user);
        System.out.println("新增记录的id值:"+user.getId());
        sqlSession.commit();

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值