zoukankan      html  css  js  c++  java
  • 【学习】017 Mybatis框架

    一、目标

    Mybatis介绍

    Mybatis增删改查

    SQL注入问题介绍

    Mybatis xml与注解实现

    Mybatis分页

    二、Mybatis快速入门

    2.1 Mybatis介绍

    MyBatis是支持普通SQL查询存储过程高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数库中的记录.JDBC ->MyBatis

    2.2 Mybatis环境搭建

    2.2.1添加Maven依赖

        <dependencies>
            <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.4</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.21</version>
            </dependency>
        </dependencies>

    2.2.2建表

    CREATE TABLE users(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), age INT);
    INSERT INTO users(name, age) VALUES('Tom', 12);
    INSERT INTO users(name, age) VALUES('Jack', 11);

    2.2.3添加mybatis配置文件

    <?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:23306/mydatabase" />
                    <property name="username" value="root" />
                    <property name="password" value="master" />
                </dataSource>
            </environment>
        </environments>
    </configuration>

    2.2.4定义表的实体类

    package com.hongmoshui.mybatis.entity;
    
    public class User
    {
        private int id;
    
        private String name;
    
        private int age;
    
        public int getId()
        {
            return id;
        }
    
        public void setId(int id)
        {
            this.id = id;
        }
    
        public String getName()
        {
            return name;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    
        public int getAge()
        {
            return age;
        }
    
        public void setAge(int age)
        {
            this.age = age;
        }
    
    }

    2.2.5定义userMapper接口

    package com.hongmoshui.mybatis.mapper;
    
    import com.hongmoshui.mybatis.entity.User;
    
    public interface UserMapper
    {
        public User getUser(int id);
    
        public Integer addUser(String name, int age);
    
        public Integer delUser(int id);
    }

    2.2.6定义操作users表的sql映射文件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="com.hongmoshui.mybatis.mapper.UserMapper">
        <select id="getUser" parameterType="int"
            resultType="com.hongmoshui.mybatis.entity.User">
            SELECT * FROM users where id =#{id}
        </select>
        <insert id="addUser"
            parameterType="com.hongmoshui.mybatis.entity.User">
            INSERT INTO users(name, age) VALUES(#{name}, #{age});
        </insert>
        <delete id="delUser" parameterType="int">
            delete from users where id=#{id}
        </delete>
    
    </mapper>

    2.2.7mybatis.xml文件中加载配置文件

        <mappers>
            <mapper resource="mapper/userMapper.xml" />
        </mappers>

    2.2.8mybatis测试方法

    package com.hongmoshui.mybatis;
    
    import java.io.IOException;
    import java.io.Reader;
    
    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.hongmoshui.mybatis.entity.User;
    
    public class TestMybatis
    {
        public static void main(String[] args) throws IOException
        {
            String resource = "mybatis.xml";
            // 读取配置文件
            Reader reader = Resources.getResourceAsReader(resource);
            // 获取会话工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            SqlSession openSession = sqlSessionFactory.openSession();
            addUser(openSession);
            delUser(openSession);
            getUser(openSession);
        }
    
        private static void getUser(SqlSession openSession)
        {
            // 查询
            String sql = "com.hongmoshui.mybatis.mapper.UserMapper.getUser";
            // 参数id
            int id = 1;
            // 调用api查询
            User user = openSession.selectOne(sql, id);
            System.out.println(user.toString());
        }
    
        private static void addUser(SqlSession openSession)
        {
            // 新增SQL
            String sql = "com.hongmoshui.mybatis.mapper.UserMapper.addUser";
            // 调用api查询
            User user = new User();
            user.setAge(19);
            user.setName("hongmoshui");
            int reuslt = openSession.insert(sql, user);
            openSession.commit();
            System.out.println(reuslt);
    
        }
    
        private static void delUser(SqlSession openSession)
        {
            // 删除SQL
            String sql = "com.hongmoshui.mybatis.mapper.UserMapper.delUser";
            // 调用api查询
            int id = 2;
            int reuslt = openSession.insert(sql, id);
            openSession.commit();
            System.out.println(reuslt);
    
        }
    }

    三、sql注入案例

    3.1创建表+测试数据

    create table user_table(  
        id      int Primary key,  
        username    varchar(30),  
        password    varchar(30)  
    );  
    insert into user_table values(1,'hongmoshui-1','12345');  
    insert into user_table values(2,'hongmoshui-2','12345');  

    3.2 jdbc进行加载

    package com.hongmoshui.mybatis;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class TestSQL
    {
        public static void main(String[] args) throws ClassNotFoundException, SQLException
        {
            String username = "hongmoshui-1";
            String password = "12345";
            String sql = "SELECT id,username FROM user_table WHERE " + "username='" + username + "'AND " + "password='" + password + "'";
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:23306/mydatabase", "root", "master");
            PreparedStatement stat = con.prepareStatement(sql);
            System.out.println(stat.toString());
            ResultSet rs = stat.executeQuery();
            while (rs.next())
            {
                String id = rs.getString(1);
                String name = rs.getString(2);
                System.out.println("id:" + id + ",name:" + name);
            }
        }
        
    }

    3.3将username的值设置为

    username='  OR 1=1 -- 或者username or 1='1

    因为--表示SQL注释,因此后面语句忽略;

    因为1=1恒成立,因此 username='' OR 1=1  恒成立,因此SQL语句等同于:

    SELECT id,username FROM user_table

    3.4sql注入解决办法

    第一步:编译sql 

    第二步:执行sql

    优点:能预编译sql语句

    package com.hongmoshui.mybatis;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class TestSQL
    {
        public static void main(String[] args) throws ClassNotFoundException, SQLException
        {
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:23306/mydatabase", "root", "master");
            // 无注入情况
            String username1 = "hongmoshui-1";
            String password1 = "12345";
            String sql1 = "SELECT id,username FROM user_table WHERE " + "username='" + username1 + "'AND " + "password='" + password1 + "'";
            selectNoInjection(con, username1, password1, sql1);
            // 注入,但是有预编译
            String username2 = "username='  OR 1=1 -- ";
            String password2 = "12345";
            String sql2 = "SELECT id,username FROM user_table WHERE username=? AND password=?";
            selectInjection(con, username2, password2, sql2);
    
        }
    
        private static void selectInjection(Connection con, String username, String password, String sql) throws SQLException
        {
            PreparedStatement stat = con.prepareStatement(sql);
            stat.setString(1, username);
            stat.setString(2, password);
            System.out.println(stat.toString());
            ResultSet rs = stat.executeQuery();
            while (rs.next())
            {
                String id = rs.getString(1);
                String name = rs.getString(2);
                System.out.println("id:" + id + "---name:" + name);
            }
        }
    
        private static void selectNoInjection(Connection con, String username, String password, String sql) throws ClassNotFoundException, SQLException
        {
            PreparedStatement stat = con.prepareStatement(sql);
            System.out.println(stat.toString());
            ResultSet rs = stat.executeQuery();
            while (rs.next())
            {
                String id = rs.getString(1);
                String name = rs.getString(2);
                System.out.println("id:" + id + ",name:" + name);
            }
        }
    
    }

    3.4 mybatis中#与$区别

    动态 sql 是 mybatis 的主要特性之一,在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析。mybatis 为我们提供了两种支持动态 sql 的语法:#{} 以及 ${}。

    在下面的语句中,如果 username 的值为 zhangsan,则两种方式无任何区别:

    select * from user where name = #{name};
    select * from user where name = ${name};

    其解析之后的结果均为

    select * from user where name = 'zhangsan';

    但是 #{} 和 ${} 在预编译中的处理是不一样的。#{} 在预处理时,会把参数部分用一个占位符 ? 代替,变成如下的 sql 语句:

    select * from user where name = ?;

    而 ${} 则只是简单的字符串替换,在动态解析阶段,该 sql 语句会被解析成

    select * from user where name = 'zhangsan';

    以上,#{} 的参数替换是发生在 DBMS 中,而 ${} 则发生在动态解析过程中。

    那么,在使用过程中我们应该使用哪种方式呢?

    答案是,优先使用 #{}。因为 ${} 会导致 sql 注入的问题。看下面的例子:

     select * from ${tableName} where name = #{name}

    在这个例子中,如果表名为

     user; delete user; -- 

      则动态解析之后 sql 如下:

    select * from user; delete user; -- where name = ?;

      --之后的语句被注释掉,而原本查询用户的语句变成了查询所有用户信息+删除用户表的语句,会对数据库造成重大损伤,极大可能导致服务器宕机。

    但是表名用参数传递进来的时候,只能使用 ${} ,具体原因可以自己做个猜测,去验证。这也提醒我们在这种用法中要小心sql注入的问题。

    3.4.1创建UserTable

    package com.hongmoshui.mybatis;
    
    public class UserTable
    {
        private int id;
    
        private String userName;
    
        private String passWord;
    
        public int getId()
        {
            return id;
        }
    
        public void setId(int id)
        {
            this.id = id;
        }
    
        public String getUserName()
        {
            return userName;
        }
    
        public void setUserName(String userName)
        {
            this.userName = userName;
        }
    
        public String getPassWord()
        {
            return passWord;
        }
    
        public void setPassWord(String passWord)
        {
            this.passWord = passWord;
        }
    
    }

    3.4.2创建UserTableMapper

    package com.hongmoshui.mybatis.mapper;
    
    import com.hongmoshui.mybatis.UserTable;
    
    public interface UserTableMapper
    {
        public UserTable login(UserTable userTable);
    }

    3.4.3userTableMapper.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="com.hongmoshui.mybatis.mapper.UserTableMapper">
        <select id="login"
            parameterType="com.hongmoshui.mybatis.UserTable"
            resultType="com.hongmoshui.mybatis.UserTable">
            SELECT id ,username as userName FROM user_table WHERE
            username=${userName} AND password=${passWord}
        </select>
    
    </mapper>

    3.4.4 mybatis.xml文件中加载配置文件

        <mappers>
            <!-- <mapper resource="mapper/userMapper.xml" /> -->
            <mapper resource="mapper/userTableMapper.xml" />
        </mappers>

    3.4.5 测试SQL注入

    package com.hongmoshui.mybatis;
    
    import java.io.IOException;
    import java.io.Reader;
    import java.sql.SQLException;
    import java.util.List;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    public class TestLoginMybatis3
    {
    
        public static void main(String[] args) throws IOException, SQLException, ClassNotFoundException
        {
    
            String resource = "mybatis.xml";
            // 读取配置文件
            Reader reader = Resources.getResourceAsReader(resource);
            // 获取会话工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            SqlSession openSession = sqlSessionFactory.openSession();
            // 查询
            String sql = "com.hongmoshui.mybatis.mapper.UserTableMapper.login";
            // 调用api查询
            UserTable userTable = new UserTable();
            userTable.setUserName("''  OR 1=1 -- ");
            userTable.setPassWord("12345");
            List<UserTable> listUserTable = openSession.selectList(sql, userTable);
            for (UserTable ub : listUserTable)
            {
                System.out.println(ub.getUserName());
            }
        }
    }

    3.4.6 总结

    优先使用 #{}。因为 ${} 会导致 sql 注入的问题

    一、Mybatis 注解使用

    Mybatis提供了增删改查注解、@select @delete @update

    4.1 建立注解Mapper

    package com.hongmoshui.mybatis.mapper;
    
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    
    import com.hongmoshui.mybatis.UserTable;
    
    public interface UserTestMapper {
        @Select("select * from user_table where id = ${id};")
        public UserTable getUser(@Param("id") int id);
    }

    4.2 加入mybatis.xml

        <mappers>
            <!-- <mapper resource="mapper/userMapper.xml" />
            <mapper resource="mapper/userTableMapper.xml" /> -->
            <mapper class="com.hongmoshui.mybatis.mapper.UserTestMapper" />
        </mappers>

    4.3 运行测试

    package com.hongmoshui.mybatis;
    import java.io.IOException;
    import java.io.Reader;
    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.hongmoshui.mybatis.mapper.UserTestMapper;
    
    public class TestMybatis3
    {
        public static void main(String[] args) throws IOException
        {
            String resource = "mybatis.xml";
            // 读取配置文件
            Reader reader = Resources.getResourceAsReader(resource);
            // 获取会话工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            SqlSession openSession = sqlSessionFactory.openSession();
            // 调用api查询
            UserTestMapper userTestMapper = openSession.getMapper(UserTestMapper.class);
            System.out.println(userTestMapper.getUser(2));
        }
    }
  • 相关阅读:
    SpringSecurity配置
    SpringBoot整合Mybatis
    springboot整合JDBC
    SpringBoot的WEB流程
    List&TreeSet实现斗地主发牌及牌序
    SpringBoot第一个程序
    项目错误总结2021.4.21
    Spring整合Mybatis
    学习——构建民航业知识图谱并实现语义查询的
    新闻文本分类——词云可视化
  • 原文地址:https://www.cnblogs.com/hongmoshui/p/10988838.html
Copyright © 2011-2022 走看看