• mybaties--day01


    1.原始JDBC操作存在的问题

    1.1原始操作流程

        public static void main(String[] args) throws SQLException, ClassNotFoundException {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            //加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            //通过驱动管理类获取数据库链接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
            //定义sql语句 ?表示占位符
            String sql = "select * from user where username = ?";
            //获取预处理statement
            preparedStatement = connection.prepareStatement(sql);
            //设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
            preparedStatement.setString(1, "王五");
            //向数据库发出sql执行查询,查询出结果集
            resultSet = preparedStatement.executeQuery();
            //遍历查询结果集
            while (resultSet.next()) {
                System.out.println(resultSet.getString("id") + "" + resultSet.getString("username"));
            }
            //释放资源
            if (resultSet != null) resultSet.close();
            if (preparedStatement != null) preparedStatement.close();
            if (connection != null) connection.close();
        }

    1.2原生JDBC操作存在问题分析:

    1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

    2、 Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

    3、 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。

    4、 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

    2.mybaties

    2.1mybaties是什么?

    mybatis是一个持久层的框架,是apache下的顶级项目。
    mxbatis 托管到goolecode下,再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)。
    mybatis 让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
    mybatis 可以将向preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射

    2.2 Mybatis架构

    1、 mybatis配置

    SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

    mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

    2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

    3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

    4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

    5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sqlid即是Mapped statementid

    6、 Mapped Statementsql执行输入参数进行定义,包括HashMap、基本类型、pojoExecutor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

    7、 Mapped Statementsql执行输出结果进行定义,包括HashMap、基本类型、pojoExecutor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

     2.3工程搭建:

    创建java工程

    所需依赖:

        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
    <!--      <scope>test</scope>-->
        </dependency>
        <!--  spring-context:导入spring核心jar包  -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.1.2.RELEASE</version>
          <!--      <scope>test</scope>-->
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.46</version>
        </dependency>
        <!--    导入日志jar包-->
        <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.2</version>
        </dependency>
        <dependency>
          <groupId>jakarta.annotation</groupId>
          <artifactId>jakarta.annotation-api</artifactId>
          <version>1.3.4</version>
        </dependency>
        <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
        </dependency>
        <dependency>
          <groupId>org.apache.logging.log4j</groupId>
          <artifactId>log4j-api</artifactId>
          <version>2.0.2</version>
        </dependency>
        <dependency>
          <groupId>org.apache.logging.log4j</groupId>
          <artifactId>log4j-core</artifactId>
          <version>2.0.2</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>1.7.5</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.7.5</version>
        </dependency>
        <!--        动态代理jar包-->
        <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>2.2.2</version>
        </dependency>
        <dependency>
          <groupId>asm</groupId>
          <artifactId>asm</artifactId>
          <version>3.3.1</version>
        </dependency>
        <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.9.2</version>
        </dependency>
        <!--        jdbcjar包-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>5.0.7.RELEASE</version>
        </dependency>
        <!--        事务支持jar包-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>5.0.7.RELEASE</version>
        </dependency>
        <!--        数据源jar包-->
        <dependency>
          <groupId>c3p0</groupId>
          <artifactId>c3p0</artifactId>
          <version>0.9.1.2</version>
        </dependency>
        <!--        另外一种数据源jar包commons-dbcp和commons-pool;-->
        <dependency>
          <groupId>commons-dbcp</groupId>
          <artifactId>commons-dbcp</artifactId>
          <version>1.4</version>
        </dependency>
        <dependency>
          <groupId>commons-pool</groupId>
          <artifactId>commons-pool</artifactId>
          <version>1.6</version>
        </dependency>
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.3.0</version>
        </dependency>
    <!--    mybaties依赖javassist-->
        <dependency>
          <groupId>org.javassist</groupId>
          <artifactId>javassist</artifactId>
          <version>3.20.0-GA</version>
        </dependency>

    编写log4j.properties

    classpath下创建log4j.properties如下:

     

    并将如下内容粘贴进去

    # Global logging configuration
    #开发环境设置成DEBUG,生产环境设置成INFO或者ERROR
    log4j.rootLogger=DEBUG, stdout
    # 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

    mybatis默认使用log4j作为输出日志信息。

     上面的内容,在我们下载mybaties的时候,里面的帮助文档里面也可以找到:

    创建SqlMapConfig.xml(名字不是SqlMapConfig也可以)

    classpath下创建SqlMapConfig.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>
        <!-- 和spring整合后 environments配置将废除-->
        <environments default="development">
            <environment id="development">
                <!-- 使用jdbc事务管理-->
                <transactionManager type="JDBC"/>
                <!-- 数据库连接池-->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="admin123"/>
                </dataSource>
            </environment>
        </environments>
    </configuration>

    SqlMapConfig.xmlmybatis核心配置文件,上边文件的配置内容为数据源、事务管理。

    3.第一个查询例子:

    需求:根据ID查询用户信息

    写一个User.java类:

    public class User {
        private int id;
        private String username;// 用户姓名
        private String sex;// 性别
        private Date birthday;// 生日
        private String address;// 地址
    ...get
    ...set
    ...toString

    数据库创建对应的表

    注意字段名要一一对应!!!并插入一条数据哦哦...

    创建sql映射文件

    classpath下的sqlmap目录下创建User类的sql映射文件usersMapper.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命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用。-->
    <mapper namespace="test">
        <!--在映射文件中配置很多sql语句-->
        <!--需求;通过id查询用户表的记录-->
        <!--通过select执行数据库查询
        id:标识映射文件中的sql将sql语句封装到mappedStatement对象中,所以将id称为statement的id
        parameterType:指定输入参数的类型,这里指定int型
        #{}表示一个占位符号
        #{id}:其中的id表示接收输入的参数,参数名称就是id,如果输入参数是简单类型,#{}中的参数名可以任意,可以value或其它名称(因为在运行过程中mybaties最终执行的sql的时候#{***}会被换成?)
        resultType:指定sql输出结果的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。
    -->
    <select id="findUserById" parameterType="int" resultType="mybaties.pojo.User">
        SELECT * FROM USER WHERE ID=#{id}
    </select>
    </mapper>

    加载映射文件

    mybatis框架需要加载映射文件,将usersMapper.xml添加在SqlMapConfig.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>
     ...
    <!--    加载映射文件-->
        <mappers>
            <mapper resource="sqlmap/userMapper.xml"></mapper>
        </mappers>
    </configuration>

    测试程序:

    import mybaties.pojo.User;
    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 java.io.IOException;
    import java.io.InputStream;
    
    public class _01Mybatis_first {
        @Test
        public void test() {
    
    //    1.配置文件
            String mapper = "SqlMapConfig.xml";
            SqlSession sqlSession = null;
    
    //    2.将配置文件加载到流
            try {
                InputStream stream = Resources.getResourceAsStream(mapper);
    //     3.创建会话工厂,传入mybaties配置文件
                SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(stream);
    //     4.通过工厂得到sqlSession
                sqlSession = sessionFactory.openSession();
    //          通过Sq1Session操作数据库
    //              第一个参数:映射文件中statement的id,等于=namespace+"."+statement的id
    //              第二个参数:指定和映射文件中所匹配的parameterType类型的参数
    //           sqlSession.selectOne()返回的结果就是映射文件中所匹配的resultType类型的对象
                User user = sqlSession.selectOne("test.findUserById", 1);
                System.out.println(user);
    //
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
    //            释放资源
                sqlSession.close();
            }
        }
    }

    4.根据用户名模糊查询用户数据:

    userMapper.xml添加如下内容:

        <!--根据用户名称模糊查询用户信息,可能返回多条
        resultType:指定就是单条记录所映射的java对象类型
        ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sq1中。
        使用${}拼接sql,引起sql注入漏洞
        ${value}:接收输入参教的内容,如果传入类型是简单类型,${}中只能使用value
        -->
    <select id="findUserByName" resultType="mybaties.pojo.User" parameterType="java.lang.String">
        SELECT *FROM USER WHERE USERNAME LIKE '%${value}%'
    </select>

    测试代码:

        @Test
        public void testByName() {
            String mapper = "SqlMapConfig.xml";
            SqlSession sqlSession = null;
            try {
                InputStream stream = Resources.getResourceAsStream(mapper);
                SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(stream);
                sqlSession = sessionFactory.openSession();
    //            List<User> list = sqlSession.selectList("test.findUserByName", "沁");
                List<User> list = sqlSession.selectList("test.findUserByName", "' OR 1=1#");
                //上面这行代码演示的是注入漏洞,最终会查询出user表所有的数据;
                // (sql语法:#后面的内容就是注释内容)
    //            所以,最终执行的SQL语句是:SELECT *FROM USER WHERE USERNAME LIKE '%' OR 1=1
                System.out.println(list);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                sqlSession.close();
            }
        }

    5.插入用户信息:

    userMapper.xml添加如下内容:

     <!--添加用户
        parameterType:指定输入参数类型是pojo(包括用户信息)
        #{}中指定poio的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值
    -->
        <insert id="insertUser" parameterType="mybaties.pojo.User">
            INSERT INTO USER (USERNAME,BIRTHDAY,SEX,ADDRESS) VALUES (#{username},#{birthday},#{sex},#{address})
        </insert>

    测试代码:

    //    插入用户信息
        @Test
    public void insertUser(){
            SqlSession session = getSession();//调用自己封装的统一获取sqlSession的方法
            User user = new User();
            user.setUsername("刘悦");
            user.setSex("1");
            user.setBirthday(new Date());
            user.setAddress("美国");
            session.insert("test.insertUser",user);
            session.commit();
            session.close();
        }

    6.插入用户信息并返回插入的最新数据的主键:

    获取自增主键:

     userMapper.xml添加如下内容:

    <!--    添加用户,并返回刚刚插入数据对应的自增主键-->
        <insert id="insertUserAndGetKey" parameterType="mybaties.pojo.User">
            <!--
            将插入数据的主键返回,返回到user对象中
            SELECT LAST_INSERT_ID():得到刚insert进去记录的主键值,只适用与自增主键
            keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性
            order:SELECT LAST_INSERT_ID()的执行顺序,相对于insert语句来说它的执行顺序
            resultType:指定SELECT LAST_INSERT_ID()的结果类型
            -->
            <selectKey keyProperty="id" resultType="java.lang.Integer" order="AFTER">
                SELECT LAST_INSERT_ID()
            </selectKey>
            INSERT INTO USER (USERNAME,BIRTHDAY,SEX,ADDRESS) VALUES (#{username},#{birthday},#{sex},#{address})
        </insert>

    演示代码:

    //    插入用户信息并获取新插入数据的自增主键
        @Test
    public void insertUserAndGetKey(){
            SqlSession session = getSession();//调用自己封装的统一获取sqlSession的方法
            User user = new User();
            user.setUsername("刘悦");
            user.setSex("1");
            user.setBirthday(new Date());
            user.setAddress("美国");
            session.insert("test.insertUserAndGetKey",user);
            System.out.println("主键:"+user.getId());
            session.commit();
            session.close();
        }

    获取非自增主键:

      userMapper.xml添加如下内容:

    <!--    添加用户,并返回刚刚插入数据对应的非增主键-->
        <insert id="insertUserAndGetKey2" parameterType="mybaties.pojo.User">
            <!--
                使用mysql的uuid()生成主键执行过程:
                首先通过uuid()得到主键,将主键设置到user对象的id属性中
                其次在insert执行时,从user对象中取出id属性值
            -->
            <selectKey keyProperty="id" resultType="java.lang.Integer" order="BEFORE">
                SELECT UUID()
            </selectKey>
            INSERT INTO USER (ID,USERNAME,BIRTHDAY,SEX,ADDRESS) VALUES (#{id},#{username},#{birthday},#{sex},#{address})
        </insert>

    补充:获取ORCAL序列主键

    userMapper.xml添加如下内容:

    <!--    添加用户,并返回刚刚插入数据对应的非增主键-->
        <insert id="insertUserAndGetKey2" parameterType="mybaties.pojo.User">
           
            <selectKey keyProperty="id" resultType="java.lang.Integer" order="BEFORE">
                SELECT 序列名.nextval()
            </selectKey>
            INSERT INTO USER (ID,USERNAME,BIRTHDAY,SEX,ADDRESS) VALUES (#{id},#{username},#{birthday},#{sex},#{address})
        </insert>

     7.删除一条数据

    userMapper.xml添加如下内容:

    <!--删除用户-->
    <!--    根据ID删除用户-->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        DELETE FROM USER WHERE ID=#{id}
    </delete>

    测试代码:

    //    删除用户信息
        @Test
    public void deleteUser(){
            SqlSession session = getSession();//调用自己封装的统一获取sqlSession的方法
            session.delete("test.deleteUser",6);
            session.commit();
            session.close();
        }

    8.更新数据

    userMapper.xml添加如下内容:

    <!--
    根据id更新用户
    分析:
    需要传入用户的id
    需要传入用户的更新信息
    parameterType指定user对象,包括id和更新信息,注意:id必须存在
    #{id}:从输入user对象中获取id属性值
    -->
    <update id="updateUser" parameterType="mybaties.pojo.User">
        UPDATE USER SET username= #{username},birthday=#{birthday},sex=#{sex},address=#{address}  WHERE ID=#{id}
    </update>

    测试程序:

    //    更新用户信息
        @Test
    public void updateUser(){
            SqlSession session = getSession();//调用自己封装的统一获取sqlSession的方法
            User user = new User();
            user.setId(5);
            user.setUsername("刘悦后");
            user.setSex("1");
            user.setBirthday(new Date());
            user.setAddress("加拿大");
            session.update("test.updateUser",user);
            System.out.println("主键:"+user.getId());
            session.commit();
            session.close();
        }

    9.mybatis和hibernate本质区别和应用场景

    hibernate:是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sql,sql语句自动生成了。
    对sql语句进行优化、修改比较困难的。
    应用场景:
    适用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。。
    mybatis:专注是sgl本身,需要程序员自己编写sgl语句,sgl修改、优化比较方便。mybatis是一个不完全的ORM框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)。
    应用场景:
    适用与需求变化较多的项目,比如:互联网项目。
    企业进行技术选型,以低成本高回报作为技术选型的原则,根据项目组的技术力量进行选择。

    10.总结原始 dao开发问题

    1、dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。
    2、调用sglsesion.方法时将statement的id硬编码了

    3、调用sglsession方法时传入的变量,由于sqlsession.方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

    11Mapper动态代理方式

    11.1 开发规范

    Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

    Mapper接口开发需要遵循以下规范:

    1、 Mapper.xml文件中的namespacemapper接口的类路径相同。

    2、  Mapper接口方法名和Mapper.xml中定义的每个statementid相同

    3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql parameterType的类型相同

    4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sqlresultType的类型相同

    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.xml文件中的namespace与mapper接口的类路径相同。-->
    <mapper namespace="mybaties.mapper.UserMapper">
        <select id="findUserById" parameterType="int" resultType="mybaties.pojo.User">
        SELECT * FROM USER WHERE ID=#{id}
        </select>
    </mapper>

    UserMapper.java:

    public interface UserMapper {
        /**
         * 2、  接口方法名和Mapper.xml中定义的每个statement的id相同
         * 3、 接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
         * 4、 接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
         */
        public User findUserById(int id) throws Exception;
    }

    selectOneselectList

    动态代理对象调用sqlSession.selectOne()sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

    mapper接口方法参数只能有一个是否影响系统开发

    系统框架中,dao层的代码是被业务层公用的。
    即使mapper接口只有一个参数,可以使用包装类型的poio满足不同的业务方法的需求。
    注意:持久层方法的参数可以包装类型、map...,service方法中建议不要使用包装类型(不利于业务层的可扩展,例如你的service方法参数是map别人调用service对应的方法时根本不知道你map里面有多少个key,或者key都是什么)

    11SqlMapConfig.xml配置文件

    11.1配置内容

    Mybaties全局配置文件:SqlMapConfig.xml中配置的内容和顺序如下:

    properties(属性)

    settings(全局配置参数)

    typeAliases(类型别名)

    typeHandlers(类型处理器)

    objectFactory(对象工厂)

    plugins(插件)

    environments(环境集合属性对象)

    environment(环境子属性对象)

    transactionManager(事务管理)

    dataSource(数据源)

    mappers(映射器)

    11.2 properties(属性)重点

    需求:

    将数据库连接参数单独配置在db.propeties.中,只需要在SqlMapconfig.xml中加载db.properties.的属性值。

    在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。

    将数据库连接参数只配置在db.eroperties.中,原因:方便对参数进行统一管理,其它xml 可以引用该db.properties。

    SqlMapconfig.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标签-->
        <properties resource="db.properties">
    <!--注意!!!properties标签内部还可以配置一下标签和属性-->
    <!--        <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>-->
        </properties>
        <!-- 和spring整合后 environments配置将废除-->
        <environments default="development">
            <environment id="development">
                <!-- 使用jdbc事务管理-->
                <transactionManager type="JDBC"/>
                <!-- 数据库连接池-->
                <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>
    
    <!--    加载映射文件-->
        <mappers>
            <mapper resource="sqlmap/userMapper.xml"></mapper>
            <mapper resource="mapper/userMapper.xml"></mapper>
        </mappers>
    </configuration>

    properties 特性:

    注意:MyBatis 将按照下面的顺序来加载属性:

    ◆在properties元素体内定义的属性首先被读取。

    然后会读取properties 元素中resource或url加载的属性,它会覆盖已读取的同名属性。

    建议:

    不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。

    在properties 文件中定义属性名要有一定的特殊性,如:xxxxx.xxxxx.xxxx

    11.3settings(全局配置参数):

    mybais框架在运行时可以调整一些运行参数。

    比如:开启二级缓存、开启延迟加载。。

    全局参数将会影响mybatis.的运行行为。

    详细参见https://blog.csdn.net/ycxzuoxin/article/details/104843730

    <?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>
    ...
        <settings>
            <setting name="" value=""/>
        </settings>
    ...
    </configuration>

    11.4typeAliases(类型别名)重点

    需求:

    在mapper.xml中,定义很多的statement,statement 需要parameterType.指定输入参数的类型、需要resultType.指定输出结果的映射类型。

    如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType.指定的类型定义一些别名,在mappe.xml中通过别名定义,方便开发。

    mybatis支持别名:

    别名

    映射的类型

    _byte

    byte

    _long

    long

    _short

    short

    _int

    int

    _integer

    int

    _double

    double

    _float

    float

    _boolean

    boolean

    string

    String

    byte

    Byte

    long

    Long

    short

    Short

    int

    Integer

    integer

    Integer

    double

    Double

    float

    Float

    boolean

    Boolean

    date

    Date

    decimal

    BigDecimal

    bigdecimal

    BigDecimal

    map

    Map

    自定义别名

    <?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>
    ...
    <!--    别名-->
        <typeAliases>
            <!--
            针对单个别名定义
            type:类型的路径
            alias:别名
            -->
            <typeAlias type="mybaties.pojo.User" alias="user"/>
            <!--
            批量别名定义
            指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写都可以)
            -->
            <package name="mybaties.pojo"/>
        </typeAliases>
    
    ...
    </configuration>

    使用别名:

        <select id="findUserById" parameterType="int" resultType="user">
        SELECT * FROM USER WHERE ID=#{id}
        </select>

    11.4mappers(映射器)重点

    Mapper配置的几种方法:

    <mapper resource="" />

    使用相对于类路径的资源

    如:<mapper resource="sqlmap/User.xml" />

    <mapper class="" />

    使用mapper接口类路径

    如:<mapper class="mybatis.mapper.UserMapper"/>

    注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

     <package name=""/>

    注册指定包下的所有mapper接口

    如:<package name="mybatis.mapper"/>

    注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

     

    !--    加载映射文件-->
        <mappers>
            <!--方法1:通过resource方法一次加载一个映射文件-->
    <!--        <mapper resource="sqlmap/userMapper.xml"></mapper>-->
            <mapper resource="mapper/UserMapper.xml"></mapper>
    
            <!--方法2:通过mapper接口加载单个映射文件
             遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中
             上边规范的前提是:使用的是mapper代理方法
             -->
    <!--        <mapper class="mybaties.mapper.UserMapper"/>-->
    
    
            <!--方法3:批里加载mapper(推荐使用)
            指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载
            遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中
            上边规范的前提是:使用的是mapper代理方法-->
    <!--        <package name="mybaties.mapper"/>-->
        </mappers>

    12 输入映射和输出映射

     Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。

    parameterType(输入类型)

    传递简单类型

    参考上面内容。

    传递pojo对象

    Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。

    传递pojo包装对象

    开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。

    Pojo类中包含pojo。

    需求:根据用户名查询用户信息,查询条件放到QueryVo的user属性中。

    Uesr类扩展类:

    /**
     * 用户扩展类
     * 假如有一天,我们项目已经上线,但是我们想扩展一下User类,而我们有不能轻易改动User,我们可以通过实现类的方式对她进行扩展
     */
    public class UserExtension extends User {
    
    
    }

    User类包装类:

    /**
     * 用户包装类
     */
    public class UserQueryVo {
    
        //    在这里包装所有需要的查询条件:下面只包装了user对象(子类)
        private UserExtension userExtension;
    
        //      ....还可以包装其他查询条件,如,订单商品,等
        public UserExtension getUserExtension() {
            return userExtension;
        }
    
        public void setUserExtension(UserExtension userExtension) {
            this.userExtension = userExtension;
        }
    }

    mapper.xml新增statement:

    <!--
            综合查询,复杂查询条件
            #{userExtension.sex}:取出用户包装类中的性别值
            ${userExtension.username}:取出用户包装类中的用户名称
            parameterType="mybaties.vo.USerQueryVo":传递进来的复杂参数都包含在USerQueryVo对象中
            resultType="mybaties.extension.UserExtension":返回值都被添加到扩展过的User子类UserExtension中(因为查询出来的内容可能包括User属性之外的内容)
    -->
        <select id="findUserList" parameterType="mybaties.vo.UserQueryVo" resultType="mybaties.extension.UserExtension">
            SELECT * FROM USER WHERE SEX=#{userExtension.sex} AND USERNAME LIKE'%${userExtension.username}%'
        </select>

    mapper.java新增查询方法:

      public List<UserExtension> findUserList(UserQueryVo queryVo) throws Exception;

    测试代码:

        @Test
        public void findUserList() throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
    //        mybaties自动生成mapper代理对象
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //        创建用户类扩展类并赋值查询条件
            UserExtension user = new UserExtension();
            user.setSex("1");
            user.setUsername("刘悦");
    //        创建用户类包装类,并给userExtension属性赋值
            UserQueryVo queryVo = new UserQueryVo();
            queryVo.setUserExtension(user);
            List<UserExtension> userList = mapper.findUserList(queryVo);
            System.out.println(userList);
        }

    传递HashMap

    <!--
    传递HashMap参数
    sex,username都是hashmap里面的key
    -->
        <select id="findUserListByMap" parameterType="hashMap" resultType="mybaties.extension.UserExtension">
            SELECT * FROM USER WHERE SEX=#{sex} AND USERNAME LIKE'%${username}%'
        </select>

    resultType(输出类型)

    使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
    如果查询出来的列名和pojo中的属性名全部不一致,没有创建 poio对象。

    只要查询出来的列名和pojo中的属性有一个一致,就会创建 pojo对象。

     输出简单类型

    <!--简单类型查询-->
    <select id="findUserListCount" resultType="int" parameterType="mybaties.vo.UserQueryVo">
        SELECT  COUNT(*)  FROM USER WHERE SEX=#{userExtension.sex} AND USERNAME LIKE'%${userExtension.username}%'
    </select>

     

    输出简单类型必须查询出来的结果集有一条记录,最终将第一个字段的值转换为输出类型。

    输出pojo对象

    参考上面内容

     输出pojo列表

    参考上面内容

    resultMap

    resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。

    如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系,resultMap实质上还需要将查询结果映射到pojo对象中。

    resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojolist实现一对一查询和一对多查询。

     mapper.xml:

    <!--    resoutMap-->
        <!--定义resultMap
        将SELECT id id_,username username_FROM USER 和User类中的属性作一个映射关系
        type:resultMap最终映射的java对象类型,可以使用别名
        id:resultMap的唯一标识-->
        <resultMap id="userResultMap" type="mybaties.pojo.User">
        <!--
        <id />表示查询结果集中唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个<id />
            column:查询出来的列名
            property:type指定的pojo类型中的属性名最终resultMap对column和property作一个映射关系(对应关系)
        -->
            <id column="id_" property="id"></id>
        <!--
        <result>:对普通名映射定义
            column:查询出来的列名
            property:type指定的pojo类型中的属性名最终resultMap对column和property作一个映射关系(对应关系)
        -->
            <result column="username_" property="username"></result>
        </resultMap>
        <!--
        使用resultMap进行输出映射
        resultMap:指定定义的resultMap的id,如果这个resultMap在其它的mapper文件,(userResultMap)前边需要加namespace的值
        -->
        <select id="findUserByIdResultMap" parameterType="int"   resultMap="userResultMap">
        SELECT id id_,username username FROM USER WHERE ID=#{id}
        </select>

     

    mapper.java:

        public User findUserByIdResultMap(int id) throws Exception;

    测试:

        @Test
        public void findUserByIdResultMap() throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.findUserByIdResultMap(5);
            System.out.println(user);
        } 

    13 动态sql:

    通过mybatis提供的各种标签方法实现动态拼接sql

    if

    需求根据查询条件是否传入,动态改变SQL,以改造下面的SQL为例:

        <select id="findUserList" parameterType="mybaties.vo.UserQueryVo" resultType="mybaties.extension.UserExtension">
            SELECT * FROM USER WHERE SEX=#{userExtension.sex} AND USERNAME LIKE'%${userExtension.username}%'
        </select>
    <!--上面的statement改为动态SQL-->
        <select id="findUserListWhitDynamicSql" parameterType="mybaties.vo.UserQueryVo" resultType="mybaties.extension.UserExtension">
             SELECT * FROM USER
    <!--where标签会去掉第一个查询条件前面的and-->
             <where>
             <if test="userExtension!=null">
                 <if test="userExtension.sex!=null and userExtension.sex!=''">
                     and SEX=#{userExtension.sex}
                 </if>
                 <if test="userExtension.username!=null and userExtension.username!=''">
                     and USERNAME LIKE'%${userExtension.username}%'
                 </if>
             </if>
             </where>
        </select>

    测试:

    //复杂参数综合查询(动态SQL)
        @Test
        public void findUserListWhitDynamicSql() throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
    //        mybaties自动生成mapper代理对象
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //        创建用户类扩展类并赋值查询条件
            UserExtension user = new UserExtension();
    
    //        由于是动态sql,某个值如果不设置,对应的查询条件就不会拼接到SQL上
    //        user.setSex("1");
    //        user.setUsername("刘悦");
    //        创建用户类包装类,并给userExtension属性赋值
            UserQueryVo queryVo = new UserQueryVo();
            queryVo.setUserExtension(user);
            List<UserExtension> userList = mapper.findUserListWhitDynamicSql(null);
            System.out.println(userList);
        }

    Sql片段

    Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的,如下:

     定义SQL片段:

        <!--    
        定义SQL片段
            id:SQL片段的唯一标识
            经验:是基于单表来定义SQL片段,这样话这个SQL片段可重用性才高
            在SQL片段中不要包括where
        -->
        <sql id="userWhere" >
            <if test="userExtension!=null">
                <if test="userExtension.sex!=null and userExtension.sex!=''">
                    and SEX=#{userExtension.sex}
                </if>
                <if test="userExtension.username!=null and userExtension.username!=''">
                    and USERNAME LIKE'%${userExtension.username}%'
                </if>
            </if>
        </sql>

    引用SQL片段

    <!--    引用Sql片段-->
        <select id="findUserListWhitDynamicSql" parameterType="mybaties.vo.UserQueryVo" resultType="mybaties.extension.UserExtension">
             SELECT * FROM USER
             <where>
            <!--如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace-->
                <include refid="userWhere"></include>
             </where>
        </select>

    foreach

     需求:

    在用户查询列表和查询总数的statement中增加多个id输入查询
    sl语句如下:
    两种方法:
    SELECT * FROM USER WHERE id=1 OR id=3 OR id=5
    SELECT*FROM USER WHERE id IN(1,3,5)

    uesr包装类添加属性:

     mapper.xml:

        <sql id="userWhere" >
            <if test="userExtension!=null">
                <if test="userExtension.sex!=null and userExtension.sex!=''">
                    and SEX=#{userExtension.sex}
                </if>
                <if test="userExtension.username!=null and userExtension.username!=''">
                    and USERNAME LIKE'%${userExtension.username}%'
                </if>
            </if>
            <if test="arrayList!=null">
                <!--如果传入的存放id的list不为null,就使用foreach遍历该arrayList
                collection:指定输入对象中集合属性名
                item:每个追历生成对象中
                open:开始遍历时拼接的串
                close:结束遍历时拼擦的串
                separator:遍历的两个对象中需要拼接的串
                -->
                <!--
                最终实现下边的sql拼接:
                AND(id=1 OR id=10 OR id=16)
                -->
                <foreach collection="arrayList" item="list_each_id" open="AND(" separator="OR" close=")">
                    ID=#{list_each_id}
                </foreach>
                <!--SELECT * FROM USER WHERE SEX=? AND ID IN( ? , ? , ? ) 拼接方法如下-->
    <!--            <foreach collection="arrayList" item="list_each_id" open="AND ID IN(" separator="," close=")">-->
    <!--                #{list_each_id}-->
    <!--            </foreach>-->
            </if>
        </sql>
    <!--  foreach:传入list参数测试-->
        <select id="findUserListWhitMuchId" parameterType="mybaties.vo.UserQueryVo" resultType="mybaties.extension.UserExtension">
             SELECT * FROM USER
    <!--where标签会去掉第一个查询条件前面的and-->
             <where>
            <!--如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace-->
                <include refid="userWhere"></include>
             </where>
        </select>

    测试:

    //foreach(传入list参数测试)
        @Test
        public void findUserListWhitMuchId() throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            UserExtension user = new UserExtension();
            user.setSex("1");
    //        user.setUsername("刘悦");
            UserQueryVo queryVo = new UserQueryVo();
            ArrayList<Integer> integers = new ArrayList<>();
            integers.add(1);
            integers.add(3);
            integers.add(5);
            queryVo.setArrayList(integers);
            queryVo.setUserExtension(user);
            List<UserExtension> userList = mapper.findUserListWhitMuchId(queryVo);
            System.out.println(userList);
        }

     

     

     

     

     

     

     


     

  • 相关阅读:
    【MongoDB详细使用教程】三、高级查询
    【MongoDB详细使用教程】二、MongoDB基本操作
    【MongoDB详细使用教程】一、Mac安装MongoDB
    【python数据分析实战】电影票房数据分析(二)数据可视化
    【python数据分析实战】电影票房数据分析(一)数据采集
    python爬取旅游数据+matplotlib简单可视化
    详解UDP协议
    MAC地址和交换机
    StringTable结构以及基本调优
    聊聊各种常量池
  • 原文地址:https://www.cnblogs.com/luzhanshi/p/13295199.html
Copyright © 2020-2023  润新知