ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Mybatis

2021-07-02 21:30:29  阅读:581  来源: 互联网

标签:username users gender mybatis pwd Mybatis id


1、框架


1.1、框架定义

框架(Framework) 是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种认为,框架是可被应用开发者定制的应用骨架、模板

简单的说,框架其实是软件的半成品,就是一组组件, 供你使用完成你自己的系统。它解决了软件过程当中的普遍性问题,从而简化了开发步骤,提高了开发的效率。

框架是安全的,可复用的,它是可以不断升级改造的软件。

框架是对某一个方面有用的,它不是全能的。

1.2、三层架构

mvc:web开发中,使用mvc架构模式。m:数据,v:视图,c:控制器

c控制器:接收请求,调用service对象,显示请求的处理结果,当前使用servlet作为控制器

v视图:使用jsp、html、css、js,显示请求的处理结果,把m中的数据显示出来

m数据:数据库mysql,文件、网络

mvc作用:

  • 实现解耦合
  • 让mvc各司其职
  • 使得系统扩展更好,更容易维护
  1. 界面层(视图层):接收用户的请求,调用service,显示请求的处理结果,包含了jsp、html、servlet等对象。对应的包controller
  2. 业务逻辑层:处理业务逻辑,使用算法处理数据的,把数据返回给界面层,对应的service包,和包中的xxxservice类,例(OrderService、Userservice)
  3. 持久层(数据访问层):访问数据库,或者读取文件,访问网络,获取数据,对应的包是dao。dao包中很多的类(OrderDao、UserDao)

1.3、三层架构请求的处理流程

用户发起请求—>界面层—>业务逻辑层---->持久层---->数据库(mysql)

为什么要使用三层架构?

  1. 结果清晰、耦合度第,各层分工明确
  2. 可维护高,可扩展性高
  3. 有利于标准化
  4. 开发人员可以只关注整个结构中的其中某一层的功能实现
  5. 有利于各层逻辑的复用

1.4、三层架构模式和框架

每一层对应着一个框架

  • 界面层—>SpringMvc框架
  • 业务逻辑层—>Spring框架
  • 持久层—>Mybatis框架

Mybatis框架:

MyBatis是一个优秀的基于java的持久层框架,内部封装了jdbc;开发者只需要关注sql语句本身,而不需要处理加载驱动、创建连接、创建statement、 关闭连接

Spring框架:

Spring框架为了解决软件开发的复杂性而创建的。Spring 使用的是基本的JavaBean来完成以前非常复杂的企业级开发。

SpringMVC框架:

Spring MVC属于SpringFrameWork 3.0版本加入的一个模块,为Spring 框架提供了构建Web应用程序的能力。

框架能解决的问题

  1. 框架能实现技术的整合
  2. 提供开发效率,减低难度

jdbc访问数据库的优缺点

优点:

  • 直观好理解

缺点:

  • 创建很多对象 Connection、Statement、RestultSet
  • 注册驱动
  • 执行sql语句
  • 把RestultSet作为Student,List集合
  • 关闭资源
  • sql语句和业务逻辑代码混在一起

2、MyBatis框架


2.1、什么是MyBatis?

  • Mybatis是apache的一个开源项目iBatis, 2010年这个项目由apacheoftware foundation 迁移到了google code, 并且改名为MyBatis 。2013年11月迁移到 Githut
  • MyBatis是一个优秀的持久层框架,支持自定义SQL,存储过程和高级映射
  • Mybatis对原有的JDBC操作进行了封装,几乎消除了所有JDBC代码,使开发者只需关注SQL本身
  • Mybatis可以使用简单的XML或Annotaion来配置执行sql,并自动完成ORM操作,将执行结果返回

ORM框架

  • ORM(Object Relational Mapping)对象关系映射,将程序中的一个对象与表中的一行数据一一对应
  • ORM框架提供了持久化与表的映射关系,在运行时参照映射文件的信息,将对象持久化到数据库中

Mybatis解决的主要问题

  • 减少使用JDBC的复杂性,不用编写重复的创建Connection、Statement;不用编写关闭资源的代码
  • 直接使用java对象,表示结果数据。让开发者专注于SQL的处理,其他分心的工作由Mybatis代劳

Mybatis能做什么?

  1. 注册驱动
  2. 创建jdbc中使用的Connection、Statement、Restult
  3. 执行sql语句,得到Restult
  4. 处理RestultSet,把记录中的数据转为java对象,同时还能把java对象放入list集合中
  5. 关闭资源
  6. 实现sql语句的和java代码的解耦合

访问与下载

3、Mybatis入门

思路:搭建环境—>导入Mybatis—>编写代码—>测试!

3.1、搭建环境

CREATE DATABASE IF NOT EXISTS `mybatis`;

USE mybatis;

CREATE TABLE `user`(
    `id` INT(20) NOT NULL,
    `name` VARCHAR(30) DEFAULT NOT NULL,
    `pwd` VARCHAR(30) DEFAULT NOT NULL,
    `gender` int(2) DEFAULT NOT NULL,
    PRIMARY KEY(id)
)ENGINE = INNODB DEFAULT CHARSET=UTF8;

INSERT INTO `user` VALUES (null,'李思','666666',1);
INSERT INTO `user` VALUES (null,'晓天','111111',0);
INSERT INTO `user` VALUES (null,'小林','888888',1);
INSERT INTO `user` VALUES (null,'李明','666666',0);
INSERT INTO `user` VALUES (null,'小米','777777',1);
  1. 新建一个普通的Maven项目

  2. 删除src目录(父工程)

  3. 导入maven依赖

    <!--导入依赖-->
    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--mybatis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <!--junit单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
    </dependencies>
    

3.2、创建一个模块

  • 编写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>
        <!--导入连接外部参数-->
        <properties resource="db.properties"/>
        <!--设置-->
        <settings>
            <!--标准的日志工厂-->
            <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
            <setting name="logImpl" value="LOG4j"/>
        </settings>
        <!--实体类别名-->
        <typeAliases>
            <!--定义类的别名-->
            <!--<typeAlias type="com.zhang.pojo.User" alias="user"/>-->
            <!--定义实体类所在的package,每个实体都会自动注册一个别名 = 类名-->
            <!--自动扫描包,将原类名作为别名-->
            <package name="com.zhang.pojo"/>
        </typeAliases>
    
        <!--核心配置信息-->
        <environments default="development">
            <!--数据库相关配置-->
            <environment id="development">
                <!--事务控制类型-->
                <transactionManager type="JDBC"/>
                <!--配置数据源:创建Connection对象-->
                <dataSource type="POOLED">
                    <!--数据连接参数-->
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${username}"/>
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
    
        <!--mapper注册-->
        <mappers>
            <!--注册mapper文件所在的位置:目的是找到其他文件的sql语句-->
            <!--
                注:resource = "mapper文件的路径,使用 / 分隔"
                一个mapper resource指定一个mapper文件
            -->
            <mapper resource="com/zhang/dao/UserDaoMapper.xml"/>
        </mappers>
    </configuration>
    
  • 编写mybatis工具类

    //sqlSessionFactory  --->sqlSession
    public class MybatisUtils {
        private static SqlSessionFactory sqlSessionFactory;
    
        static {
            try {
                //使用Mybatis第一步:获取sqlSessionFactory
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例
        //SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
        public static SqlSession getSqlSession() {
            return sqlSessionFactory.openSession();
        }
    }
    

3.3、编写代码

  • 实体类

    package com.zhang.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    /**
     * 和数据库中的字段做映射
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class User {
        private int id;
        private String userName;
        private String pwd;
        private int gender;
    }
    
  • Dao接口

    package com.zhang.dao;
    
    import com.zhang.pojo.User;
    
    import java.util.List;
    
    public interface UserDao {
        //查询所有用户
        List<User> selectAllUsers();
    }
    
  • 接口实现类由原来的UserDaoImpl转变为一个Mapper配置文件

    <?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 namespace="com.zhang.dao.UserDao">
        <!--id = 所需重写的接口抽象方法名  resultType = 查询后所需返回的对象类型-->
        <select id="selectAllUsers" resultType="user">
            select id, id, username, pwd, gender
            from mybatis.users
        </select>
    </mapper>
    
    <!--
                1.约束文件
                "http://mybatis.org/dtd/mybatis-3-mapper.dtd"
                约束文件作用:定义和限制当前文件中可以使用的标签和属性,以及标签出现的顺序
                2.mapper是根标签
                namespace:命名空间,必须有值,不能为空,唯一值
                推荐使用Dao接口的全限定名称
                3.在mapper标签中可以写<insert>、<delete>、<update>、<select>等标签
            -->
    

3.4、测试

注:org.apache.ibatis.binding.BindingException: Type interface com.zhang.dao.UserDao is not known to the MapperRegistry.

解决方案:核心配置文件中注册mappers

  • junit测试

    package com.zhang;
    
    import com.zhang.dao.UserDao;
    import com.zhang.pojo.User;
    import com.zhang.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.List;
    
    public class TestUserDao {
        @Test
        public void testSelectUserById() {
            //第一步:获得sqlSession对象
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            //方式一:getMapper  推荐使用
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            List<User> users = mapper.selectAllUsers();
            for (User user : users) {
                System.out.println(user);
            }
    
            //方式二:需要转换
            //List<User> userList = sqlSession.selectList("com.zhang.dao.UserDao.selectAllUsers");
            //for (User user : userList) {
            //    System.out.println(user);
            //}
            //关闭sqlSession
            sqlSession.close();
        }
    }
    

注:Could not find resource com/zhang/dao/UserDaoMapper.xml

解决方案:由于maven约定大于配置,在pom.xml的文件中修改maven的默认规则

<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
    <!--更改maven编译规则-->
    <resources>
        <resource>
            <!--资源目录-->
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

4、CRUD

4.1、select

标签:

4.1.1、序号参数绑定

public interface UserDao {
    //根据用户id和姓名查询用户
    User selectUserByIdAndUserName(Integer id, String userName);        //原生参数绑定
}
<select id="selectUserByIdAndUserName" resultType="user">
    select id, username, pwd, gender
    from mybatis.users
    where id = #{arg0}
    and username = #{arg1}		<!--arg0、arg1、arg2、argn-->
</select>

<select id="selectUserByIdAndUserName" resultType="user">
    select id, username, pwd, gender
    from mybatis.users
    where id = #{param1}
    and username = #{param2}	<!--param1、param2、param3、param(n)-->
</select>

4.1.2、注解参数绑定(推荐)

import org.apache.ibatis.annotations.Param;     //引入注解

public interface UserDao {
    //根据用户id和密码查询用户
    User selectUserByIdAndPassword(@Param("id") Integer id, @Param("password") String password);        //使用Mybatis提供的@Param进行参数绑定
}
<select id="selectUserByIdAndPassword" resultType="user">
    select id, username, pwd, gender
    from mybatis.users
    where id = #{id}
    and pwd = #{password}     <!--使用注解值@param{pwd}-->
</select>

4.1.3、Map参数绑定

public interface UserDao {
    User selectUserByUserNameAndPassword(Map values);        //添加Map进行参数绑定
}

UserDao mapper = sqlSession.getMapper(UserDao.class);
Map values = new HashMap();        //测试类创建Map
values.put("myusername", "李思");      //自定义key,绑定参数
values.put("mypwd", "666666");
User user = mapper.selectUserByUserNameAndPassword(values);
<select id="selectUserByUserNameAndPassword" resultType="user">
    select id, username, pwd, gender
    from mybatis.users
    where username = #{myusername}
    and pwd = #{mypwd}          <!--通过key获取value-->
</select>

4.1.4、对象参数绑定

public interface UserDao {
    User selectUserByUserNameAndPassword1(User user);       //使用对象进行参数绑定
}
<select id="selectUserByUserNameAndPassword1" resultType="user">
    select id, username, pwd, gender
    from mybatis.users
    where username = #{userName}
    and pwd = #{pwd}          <!--#{userName}取User对象的userName属性值,#{pwd}同理-->
</select>

4.1.5、模糊查询

public interface UserDao {
    List<User> selectByUserNameLike(@Param("keyword") String userName);     //根据用户名模糊查询
}
<select id="selectByUserNameLike" resultType="user">
    select id, username, pwd, gender
    from mybatis.users
    where username like concat('%',#{keyword},'%')         <!--使用mysql  concat拼接 '%'-->
</select>

4.2、delete

标签:<delete id = “” parameterType=""

<delete id="deleteUserById" parameterType="int">
    delete
    from mybatis.users
    where id = #{id}
</delete>

4.3、update

<update id="updateUserById" parameterType="user">
    update mybatis.users
    set username = #{userName},
        pwd      = #{pwd},
        gender   = #{gender}
    where id = #{id}        <!--方法参数为对象时,可直接使用#{属性名}获取-->
</update>

4.4、insert

<insert id="addUser" parameterType="user">
    insert into mybatis.users
    values (#{id}, #{userName}, #{pwd}, #{gender});
    insert into mybatis.users
    values (null, #{userName}, #{pwd}, #{gender});		<!--自动主键-->
</insert>

注:增、删、改需要提交事务!

4.5、主键回填

4.5.1、通过last-insert_id()查询主键

<insert id="addUser" parameterType="user">
    <!--主键回填,将新数据的ID,存入java对象和主键对应的属性中-->
    <selectKey order="AFTER" resultType="int" keyProperty="id">    <!--插入之后-->
        select last_insert_id()     <!--适用于整数类型自增主键-->
    </selectKey>
    insert into mybatis.users
    values (#{id}, #{userName}, #{pwd}, #{gender});
</insert>

4.5.2、通过uuid()查询主键

<insert id="addStudent" parameterType="student">
    <selectKey order="BEFORE" keyProperty="id" resultType="string">   <!--插入之前-->
        select replace(uuid(),'-','')       <!--适用于字符串类型主键-->
    </selectKey>
    insert into mybatis.student values (#{id},#{name},#{age})
</insert>

5、配置解析


5.1、核心配置文件

  • mybatis-config.xml

  • Mybatis配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。

    configuration(配置)
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
    environment(环境变量)
    transactionManager(事务管理器)
    dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)

5.2、环境配置(environments)

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

Mybatis默认的事务管理器就是JDBC,连接池:POOLED

5.3、属性(properties)

可以通过properties属性来引用配置文件;

这些属性可以在外部配置且进行动态替换。既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties

编写一个配置文件

db.properties

#key=value
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8
username = root
password = root

在核心配置文件中映入

<!--引入web配置文件-->
<properties resource="db.properties">
    <property name="username" value="root"/>
    <property name="pwd" value="root"/>
</properties>
  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件

5.4、类型别名(typeAliases)

  • 类型别名可为 Java 类型设置一个缩写名字

  • 它仅用于 XML 配置,意在降低冗余的全限定类名书写

    <!--可以给实体类起别名-->
    <typeAliases>
        <typeAlias type="com.zhang.pojo.Users" alias="user"/>
    </typeAliases>
    

    也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

    扫描实体类的包,它的默认别名就为这个类的类名:首字母小写

    <!--可以给实体类起别名-->
    <typeAliases>
        <package name="com.zhang.pojo"/>
    </typeAliases>
    

在实体类比较少的时候,使用第一种方式

如果实体类十分多,推荐使用第二种

第一种可以DIY(自定义)别名,第二种则不行(可以通过注解添加别名

@Alias("user")
public class Users {
    private int id;
    //......
}

5.5、设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为;

5.6、其他配置

5.7、映射器(mappers)

MapperRegistry:注册绑定我们的mapper文件;

方式一:【推荐使用】

<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<mappers>
    <mapper resource="com/zhang/dao/UserMapper.xml"/>
</mappers>

方式二:使用class文件绑定注册

<mappers>
    <mapper class="com.zhang.dao.UserMapper"/>
</mappers>

注:

  • UserMapper接口要和它的UserMapper.xml配置文件必须同名!并且必须在同一包下

方式三:使用扫描包进行注入绑定

<mappers>    
    <package name="com.zhang.dao"/>
</mappers>

注意点:使用同方式二一致!

6、日志


6.1、什么是日志?

用于记录系统中发生的各种事件。记录的位置常见的有:控制台、磁盘文件等

日志的级别

日志级别从低到高:

TRACE、DEBUG、 INFO、 WARN、 ERROR、FATAL

日志的作用

  • 通过日志观察、分析项目的运行情况(项目维护)
  • 通过日志分析用户的使用情况(大数据分析)
  • ……

  • SLF4J
  • LOG4J
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING (控制台输出)
  • NO_LOGGING

在Mybatis中具体使用那个日志实现,在设置中设定!

STDOUT_LOGGING标准日志输出

在mybatis核心配置文件中,配置日志!

<settings>
    <!--标准的日志工厂-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

6.2、Log4j+Commons-Logging

什么是log4j?

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
  • 我们也可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
  • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
  1. 导入依赖

    项目中添加Log4j和Commons-Logging依赖

    <dependencies>
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
    
  2. 基本使用

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.junit.Test;
    
    public class LogTest {
        //日志对象
        private Log log = LogFactory.getLog(LogTest.class);     //需要输出日志的类,可以创建一个log属性
    
        @Test
        public void testLog(){
            log.trace("hello trace~~");
            log.debug("hello debug~~");
            log.info("hello info~~");
            log.warn("hello warn~~");
            log.error("hello error~~");
            log.fatal("hello fatal~~");
        }
    }
    
  3. 配置信息

    定义配置文件log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">

<log4j:configuration>

    <!-- 日志输出到控制台 -->
    <appender name="myConsole" class="org.apache.log4j.ConsoleAppender">
        <!-- 日志输出格式 -->
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%p][%-d{yyyy-MM-dd HH:mm:ss SSS}][%c]-[%p] %m%n"/>
        </layout>

        <!--过滤器设置输出的级别-->
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <!-- 设置日志输出的最小级别 -->
            <param name="levelMin" value="TRACE"/>
            <!-- 设置日志输出的最大级别 -->
            <param name="levelMax" value="FATAL"/>
        </filter>
    </appender>


    <!-- 输出日志到文件 -->
    <appender name="myFile" class="org.apache.log4j.FileAppender">
        <!-- 输出文件全路径名-->
        <param name="File" value="d:/log/fileAppender.log"/>
        <!--是否在已存在的文件追加写:默认时true,若为false则每次启动都会删除并重新新建文件-->
        <param name="Append" value="false"/>
        <param name="Threshold" value="INFO"/>
        <!--是否启用缓存,默认false-->
        <param name="BufferedIO" value="false"/>
        <!--缓存大小,依赖上一个参数(bufferedIO), 默认缓存大小8K  -->
        <param name="BufferSize" value="512"/>
        <!-- 日志输出格式 -->
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%p][%d{yyyy-MM-dd HH:mm:ss SSS}][%c]-[%m]%n"/>
        </layout>
    </appender>


    <!-- 输出日志到文件,当文件大小达到一定阈值时,自动备份 -->
    <!-- FileAppender子类 -->
    <appender name="rollingAppender" class="org.apache.log4j.RollingFileAppender">
        <!-- 日志文件全路径名 -->
        <param name="File" value="d:/log/rollingAppender.log"/>      <!--文件位置-->
        <!--是否在已存在的文件追加写:默认时true,若为false则每次启动都会删除并重新新建文件-->
        <param name="Append" value="true"/>
        <!-- 保存备份日志的最大个数,默认值是:1  -->
        <param name="MaxBackupIndex" value="10"/>
        <!-- 设置当日志文件达到此阈值的时候自动回滚,单位可以是KB,MB,GB,默认单位是KB,默认值是:10MB -->
        <param name="MaxFileSize" value="10KB"/>
        <!-- 设置日志输出的样式 -->`
        <layout class="org.apache.log4j.PatternLayout">
            <!-- 日志输出格式 -->
            <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%-5p] [method:%l]%n%m%n%n"/>
        </layout>
    </appender>


    <!-- 日志输出到文件,可以配置多久产生一个新的日志信息文件 -->
    <appender name="dailyRollingAppender" class="org.apache.log4j.DailyRollingFileAppender">
        <!-- 文件文件全路径名 -->
        <param name="File" value="d:/log/dailyRollingAppender.log"/>
        <!--是否追加-->
        <param name="Append" value="true"/>
        <!-- 设置日志备份频率,默认:为每天一个日志文件 -->
        <param name="DatePattern" value="'.'yyyy-MM-dd'.log'"/>

        <!--每分钟一个备份-->
        <!--<param name="DatePattern" value="'.'yyyy-MM-dd-HH-mm'.log'" />-->
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%p][%d{HH:mm:ss SSS}][%c]-[%m]%n"/>
        </layout>
    </appender>


    <!--
        1. 指定logger的设置,additivity是否遵循缺省的继承机制
        2. 当additivity="false"时,root中的配置就失灵了,不遵循缺省的继承机制
        3. 代码中使用Logger.getLogger("logTest")获得此输出器,且不会使用根输出器
    -->
    <logger name="logTest" additivity="false">
        <level value="INFO"/>
        <appender-ref ref="dailyRollingAppender"/>
    </logger>


    <!-- 根logger的设置,若代码中未找到指定的logger,则会根据继承机制,使用根logger-->
    <root>
        <!--优先级设置:all < trace < debug < info < warn < error < fatal < off-->
        <priority value="all"/>
        <appender-ref ref="myConsole"/>
        <appender-ref ref="fileAppender"/>
        <appender-ref ref="rollingAppender"/>
        <appender-ref ref="dailyRollingAppender"/>
    </root>

</log4j:configuration>

log4j

7、Mybatis工具类


7.1、封装工具类

  • Resource:用于获得读取配置文件的I0对象,耗费资源,建议通过10-次性读取所有所需要的数据。
  • SlSessionFactory: SqlSession工 类,内存占用多,耗费资源,建议每个应用只创建一个对象。
  • SqlSession:相当于Connection, 可控制事务,应为线程私有,不被多线程共享。
  • 将获得连接、关闭连接、提交事务、回滚事务、获得接口实现类等方法进行封装。
package com.zhang.utils;

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 java.io.IOException;
import java.io.InputStream;

/**
 * 1、加载配置
 * 2、构建SqlSessionFactory
 * 3、创建SqlSession
 * 4、事务的管理
 * 5、Mapper的获取
 */
public class MybatisUtils {
    //创建ThreadLocal绑定当前线程中的SqlSession对象
    private static final ThreadLocal<SqlSession> t1 = new ThreadLocal<SqlSession>();
    private static SqlSessionFactory sqlSessionFactory;

    static {        //加载配置信息,并构建sqlSessionFactory
        try {
            //1.加载配置文件
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //2.构建sqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //通过sqlSessionFactory创建SqlSession
    //SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
    public static SqlSession getSqlSession() {
        //线程唯一,全局不唯一
        SqlSession sqlSession = t1.get();
        if (sqlSession == null) {
            sqlSession = sqlSessionFactory.openSession();
            t1.set(sqlSession);
        }
        return sqlSession;
    }

    //事务提交
    public static void commit() {
        SqlSession sqlSession = getSqlSession();
        sqlSession.commit();
        closeSqlSession();
    }

    //事务回滚
    public static void rollback() {
        SqlSession sqlSession = getSqlSession();
        sqlSession.rollback();
        closeSqlSession();
    }

    //资源释放
    public static void closeSqlSession() {
        SqlSession sqlSession = t1.get();
        if (sqlSession != null) sqlSession.close();
    }

    //获取Mapper
    public static <T> T getMapper(Class<T> mapper) {
        SqlSession sqlSession = getSqlSession();
        return sqlSession.getMapper(mapper);
    }
}

编写测试类,可以看出,步骤简化很多了

package com.zhang;

import com.zhang.dao.StudentDao;
import com.zhang.pojo.Student;
import com.zhang.utils.MybatisUtils;
import org.junit.Test;

public class TestStudentDao {
    @Test
    public void testAddStudent() {
        StudentDao mapper = MybatisUtils.getMapper(StudentDao.class);
        Student s1 = new Student(null, "testUtil", "18");
        mapper.addStudent(s1);
        System.err.println(s1.getId());
        MybatisUtils.commit();
        MybatisUtils.closeSqlSession();
    }
}

8、使用注解开发


8.1、面向接口编程

  • 大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
  • 根本原因:解耦 ,可拓展、提高复用、分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好
  • 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
  • 而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

关于接口的理解

  • 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
  • 接口的本身反映了系统设计人员对系统的抽象理解。
  • 接口应有两类:
    • 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);
    • 第二类是对一个个体某一方面的抽象, 即形成-一个抽象面(interface) ;
  • 一个体有可能有多个抽象面。抽象体与抽象面是有区别的。

三个面向区别

  • 面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法
  • 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现
  • 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程) 不是一个问题,更多的体现就是对系统整体的架构

8.2、使用注解开发

通过在接口中直接添加Mybatis注解,完成CRUD

@Select("  select id, username, pwd, gender from mybatis.users")
List<User> getusers();

需要在核心配置文件中绑定接口!

<mappers>
    <!--<mapper resource="com/zhang/dao/UserDaoMapper.xml"/>-->
    <mapper class="com.zhang.dao.UserDao"/>			<!--class="接口全限定名"-->
</mappers>

注:接口注解定义完毕后,需将接口全限定名注册到mybatis-config.xml的< mappers >中

经验:注解模式属于硬编码到java文件中,失去了使用配置文件外部修改的优势,可结合需求选用。

本质:反射机制实现

底层:动态代理

8.2.1、查询

public interface UserDao {
    @Select("  select id, username, pwd, gender from mybatis.users")
    List<User> queryAllUser();

    @Select("select id, username, pwd, gender from mybatis.users where id = #{id}")
    User queryUserById(@Param("id") Integer id);
}

8.2.2、删除

public interface UserDao {
    @Delete("delete from mybatis.users where id = #{id}")
    Integer deleteUser(@Param("id") Integer id);
}

8.2.3、添加

public interface UserDao {
    @Options(useGeneratedKeys = true,keyProperty = "id")        //自增key,主键为id
    @Insert(" insert into mybatis.users values (null, #{username}, #{pwd}, #{gender})")
    Integer insertUser(User user);
}

8.2.4、修改

public interface UserDao {
    @Update("update mybatis.users set username=#{username},pwd=#{pwd},gender=#{gender} where id=#{id}")
    Integer updateUser(User user);
}

9、ORM映射


9.1、Mybatis自动ORM失效

MyBatis只能自动维护库表”列名“与”属性名“相同时的一-对应关系, 二者不同时,无法自动ORM。

9.2、方案一:列的别名

在SQL中使用as为查询字段添加列别名,以匹配属性名。

<mapper namespace="com.zhang.dao.PersonDao">
    <select id="selectAllPerson" resultType="person">
        select id, username as name, password as pwd, gender as sex
        from mybatis.person
    </select>
</mapper>

9.3、方案二:结果集映射(ResultMap-查询结果的封装规则)

通过映射,匹配列名与属性名

<mapper namespace="com.zhang.dao.PersonDao">    <!--使用resultMap标签定义更复杂的映射规则-->    <resultMap id="person_resultMap" type="person">        <!--关联主键与列名-->        <id column="id" property="id"></id>        <!--关联列名与属性-->        <result column="username" property="name"></result>        <result column="password" property="pwd"></result>        <result column="gender" property="sex"></result>    </resultMap>    <!--使用resultMap作为ORM映射-->    <select id="selectAllPerson" resultMap="person_resultMap">        select id, username, password, gender        from mybatis.person    </select></mapper>

10、Mybatis处理关联关系-多表连接


实体间的关系:关联关系(拥有has、属于belong)

  • OneToOne:一对一关系(Passenger(旅客)-- Passport(护照))
  • OneToMany:一对多关系 (Employee(员工) 一Department(部门))
  • ManyToMany:多对多关系(Student(学生) – Subject(科目))

10.1、OneToOne

环境搭建

create table t_passengers(    `id` int primary key auto_increment,    name varchar(50),    sex varchar(1),    birthday date)default charset = utf8;create table t_passports(    id int auto_increment primary key ,    nationality varchar(50),    expire date,    passenger_id int unique ,    foreign key (passenger_id) references t_passengers(id))default charset  = utf8;insert into t_passengers values (null,'张绍刚','男','2002-1-1');insert into t_passengers values (null,'李晓峰','男','2001-5-15');insert into t_passengers values (null,'林晓东','男','1999-6-15');insert into t_passports values (null,'中国','2035-1-1',1);insert into t_passports values (null,'美国','2050-1-1',2);insert into t_passports values (null,'英国','2040-1-1',3);
<mapper namespace="com.zhang.dao.PassengerDao">    <!--结果集映射(查询结果的封装规则)-->    <resultMap id="passenger_passport" type="passenger">        <id column="id" property="id"></id>        <result column="name" property="name"></result>        <result column="sex" property="sex"></result>        <result column="birthday" property="birthday"></result>        <!--关系表中数据的封装规则-->        <!--描述passport nationality expire-:映射规则-->        <association property="passport" javaType="passport">            <!--指定关系表的实体属性-->            <id column="passId" property="id"></id>            <result column="nationality" property="nationality"></result>            <result column="expire" property="expire"></result>        </association>    </resultMap>    <!--查询旅客及其护照信息-->    <!--多表连接查询-->                     <!--结果集映射(查询结果的封装规则)-->    <select id="queryPassengerById" resultMap="passenger_passport">        <!--别名,避免id冲突-->        select enger.id, name, sex, birthday, passenger_id passId, port.nationality, port.expire        from t_passengers as enger        inner join t_passports as port        on enger.id = port.passenger_id        where enger.id = #{id}    </select></mapper>

10.2、OneToMany

环境搭建

create table t_departments(    id int primary key auto_increment,    name varchar(50),    location varchar(100))default charset  = utf8;create table t_employees(    id int primary key auto_increment,    name varchar(50),    salary double,    dept_id int,    foreign key (dept_id) references t_departments(id))default charset = utf8;insert into t_departments values (null,'研发部','北京'),(null,'教学部','上海'),(null,'品牌部','西安');insert into t_employees values (null,'李晓明',10000,1),(null,'林小芳',6000,1),(null,'张立伟',8000,2),(null,'赵伟峰',8800,2),(null,'林晓鸥',12000,3),(null,'赵凯峰',11000,3)
<mapper namespace="com.zhang.dao.DepartmentDao">    <!--封装规则-->    <resultMap id="dept_emp" type="department">        <id column="id" property="id"></id>        <result column="name" property="name"></result>        <result column="location" property="location"></result>        <!--emp_id  emp_name  salary   employee-->        <!--关系表中数据的封装骨规则-->         <!--指定关系表的实体类型-->        <collection property="employee" ofType="Employee">            <id column="emp_id" property="id"></id>            <result column="emp_name" property="name"></result>            <result column="salary" property="salary"></result>        </collection>    </resultMap>    <!--多表连接查询-->                   <!--封装规则-->    <select id="queryDepartmentById" resultMap="dept_emp">        <!--别名,避免id冲突-->        select d.id, d.name, location, emp.id emp_id, emp.name emp_name, emp.salary        from t_departments d        inner join t_employees emp        on d.id = emp.dept_id        where dept_id = #{id}    </select></mapper>

10.3、ManyToMany

环境搭建

create table t_student(    id   int primary key auto_increment,    name varchar(50),    sex  varchar(1)) default charset = utf8;create table t_subject(    id    int primary key auto_increment,    name  varchar(50),    grade varchar(1)) default charset = utf8;create table t_stu_sub(    student_id int,    subject_id int,    foreign key (student_id) references t_student (id),    foreign key (subject_id) references t_subject (id),    primary key (student_id, subject_id)) default charset = utf8;insert into t_student values (null,'小张','男'),(null,'小林','女');insert into t_subject values (1001,'JavaSE','1'),(1002,'JavaWeb','2');insert into t_stu_sub values (1,1001),(1,1002),(2,1001),(2,1002);
<mapper namespace="com.zhang.dao.SubjectDao">    <!--映射查询只封装两表中的信息,可忽略关系表内容-->    <resultMap id="subject_student" type="subject">        <id column="sub_id" property="id"></id>        <result column="sub_name" property="name"></result>        <result column="grade" property="grade"></result>        <collection property="studentList" ofType="student">            <id column="stu_id" property="id"></id>            <result column="stu_name" property="name"></result>            <result column="sex" property="sex"></result>        </collection>    </resultMap>    <!--三表连接查询-->                   <!--封装规则-->    <select id="querySubjectById" resultMap="subject_student">        select subject_id sub_id,sub.name sub_name,grade,t_student.id stu_id,t_student.name stu_name,sex        from t_student inner join t_subject sub        on t_student.id = sub.id      <!--通过t_stu_sub建立两者之间的关系-->        join t_stu_sub        on t_student.id = t_stu_sub.student_id        where subject_id = #{id}    </select></mapper>

注:指定"多方"关系时(集合),使用

JavaType用来指定实体类中属性的类型

ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

10.4、关系总结

一方,添加对象;多方,添加集合。

双方均可建立关系属性,建立关系属性后,对应的Mapper文件中需使用< ResultMap >完成多表映射。

持有对象关系属性,使用< association property=“dept” javaType="department >

持有集合关系属性,使用< collction property=“emps” ofType="employee >

11、动态SQL


MyBatis的映射文件中支持在基础SQL上添加一些逻辑操作,并动态拼接成完整的SQL之后再执行,以达到SQL复用、简化编程的效果

11.1、 SQL

<mapper namespace="com.zhang.dao.UserDao">    <!--抽取通用的sql片段-->    <sql id="user_field">        select id, username, pwd, gender        from mybatis.users    </sql>    <select id="queryAllUser" resultType="user">        <!--通过ID引用sql片段-->        <include refid="user_field"></include>    </select></mapper>

11.2、where

<mapper namespace="com.zhang.dao.UserDao">    <select id="queryUsers" resultType="user">        <include refid="user_field"></include>        <!--where标签:        1.补充where关键字        2.where字句中以or、and开头,会将or、and去掉    -->        <where>            <if test="username!=null">username=#{username}</if>            <if test="gender!=null">and gender=#{gender}</if>        </where>    </select></mapper>

11.3、set

<mapper namespace="com.zhang.dao.UserDao">    <update id="updateUser" parameterType="user">        update mybatis.users        <!--            set标签:                1.补充set                2.自动将set字句的,去除            -->        <set>            <if test="username!=null">username=#{username},</if>            <if test="pwd!=pwd">pwd=#{pwd},</if>            <if test="gender!=gender">gender=#{gender},</if>        </set>        where id = #{id}    </update></mapper>

11.4、trim

代替where、set

<mapper namespace="com.zhang.dao.UserDao">    <select id="queryUsers" resultType="user">        <include refid="user_field"></include>        <!--            prefix="where" 补充where关键字            prefixOverrides  where字句以or或and开头,会被去除掉        -->        <trim prefix="where" prefixOverrides="or|and">		<!--添加where前缀,自动忽略前缀-->            <if test="username!=null">username=#{username}</if>            <if test="gender!=null">and gender=#{gender}</if>        </trim>    </select></mapper>
<mapper namespace="com.zhang.dao.UserDao">	 update mybatis.users        <!--             prefix="set" 补充set关键字             suffixOverrides  自动将set字句的,去除        -->        <trim prefix="set" suffixOverrides=",">		<!--添加set前缀,自动忽略后缀-->            <if test="username!=null">username=#{username},</if>            <if test="pwd!=pwd">pwd=#{pwd},</if>            <if test="gender!=gender">gender=#{gender},</if>        </trim>        where id = #{id}    </update></mapper>

11.5、foreach

<mapper namespace="com.zhang.dao.UserDao">    <!--批量删除-->    <delete id="deleteManyUser" parameterType="java.util.List">        <!--delete from mybatis.users where id in(x,x,x,x)-->        delete from mybatis.users where id in        <foreach collection="list" open="(" close=")" item="id6" separator=",">            #{id6}        </foreach>    </delete>    <!--批量添加-->    <insert id="insertManyUser" parameterType="java.util.List">        <!--insert into mybatis.users values (null,x,x,x),(null,x,x,x)-->        insert into mybatis.users values        <foreach collection="list" item="user6" separator=",">            (null,#{user6.username},#{user6.pwd},#{user6.gender})        </foreach>    </insert></mapper>
参数描述取值
collection容器类型list、array、map
open起始符(
close结束符)
separator分隔符,
index下标号从0开始,依次递减
item当前项任意名称(循环中通过#{任意名称}表达式访问)

12、缓存(Cache)


内存中的一块存储空间,服务于某个应用程序,旨在将频繁读取的数据临时保存在内存中,便于二次快速访问。

12.1、一级缓存

SqlSession级别的缓存,同一个SqlSession的发起多次同构查询, 会将数据保存在一级缓存中。

注:无需任何配置,默认开启一级缓存

12.2、二级缓存

SqlSessionFactory级别的缓存, 同一个SqlSessionFactory构建的SqlSession发起的多次同构查询,会将数据保存在二级缓存中

注:在Sqlsession.commit()或者Sqlsession.close()之后生效

12.2.1、开启全局缓存

setting是Mybatis中极为重要的调整位置,他们会改变Mybatis的运行行为,其他详细配置可参考官方文档

<configuration>    <!--导入连接外部参数-->    <properties resource="db.properties"/>    <!--设置-->    <settings>   <!--注意书写位置-->        <setting name="cacheEnabled" value="true"/>     <!--mybatis-config.xml中开启全局缓存(默认开启)-->    </settings>    <typeAliases>        <package name="com.zhang.pojo"/>    </typeAliases></configuration>

12.2.2、指定Mapper缓存

<mapper namespace="com.zhang.dao.UserDao">    <!--二级缓存是默认开启的,但并不是所有的查询结果,都会进入二级缓存(相当于邀请函)-->    <cache/></mapper>

12.2.3、缓存清空并重新缓存

@Testpublic void testMapperCache(){    //通过相同的sqlSessionFactory获取多个SqlSession    SqlSession sqlSession1 = MybatisUtils.openSqlSession();    UserDao mapper1 = sqlSession1.getMapper(UserDao.class);    List<User> users1 = mapper1.queryAllUser();    sqlSession1.close();        //必须关闭sqlSession才可缓存数据    //修改  修改相关的数据,会被移除    SqlSession sqlSession4 = MybatisUtils.openSqlSession();    UserDao mapper4 = sqlSession4.getMapper(UserDao.class);    Integer i = mapper4.deleteUser(5010);    sqlSession4.commit();       //DML成功,数据发生变化,缓存清空    sqlSession4.close();    SqlSession sqlSession2 = MybatisUtils.openSqlSession();    UserDao mapper2 = sqlSession2.getMapper(UserDao.class);    System.out.println("***************");    List<User> users2 = mapper2.queryAllUser();    sqlSession2.close();        //缓存未击中,重新查询数据库、重新缓存    System.out.println("-----------------");    SqlSession sqlSession3 = MybatisUtils.openSqlSession();    UserDao mapper3 = sqlSession3.getMapper(UserDao.class);    List<User> users3 = mapper3.queryAllUser();    sqlSession2.close();}

13、Druid连接池


13.1、什么是Druid连接池?

Druid是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和SQL解析器组成。该项目主要是为了扩展JDBC的一些限制,可以让程序员实现一些特殊的需求,比如向密钥服务请求凭证、统计SQL 信息、SQL 性能收集、SQL 注入检查、SQL 翻译等,程序员可以通过定制来实现自己需要的功能。

13.2、不同连接池对比

测试执行申请归还连接1000000(一百万)次总耗时性能对比

13.1.1、测试环境

环境版本
OSOS X 10.8.2
CPUIntel i7 2GHz 4 Core
JVMJava Version 1.7.0_05

13.1.2、基准测试结果对比

  • Druid是性能最好的数据库连接池,tomcat-jdbc和druid性能接近。
  • Proxool在激烈并发时会抛异常,不适用。
  • C3P0和Prool都相当慢,影响sql执行效率。
  • BoneCP性能并不优越,采用LinkedTransterQueue并没有能够获得性能提升。
  • 除了bonecp, 其他的在JDK7. 上跑得比JDK6上快。
  • jboss datasource虽然稳定,但性能很糟糕。

13.3、配置pom.xml

在pom.xml引入Druid依赖

<!--druid连接池--><!-- https://mvnrepository.com/artifact/com.alibaba/druid --><dependency>    <groupId>com.alibaba</groupId>    <artifactId>druid</artifactId>    <version>1.1.22</version></dependency>

13.4、创建DruidDataSourceFactory

MyDruidDataSourceFactory并继承PooledDataSourceFactory,并替换数据源。

package com.zhang.utils;import com.alibaba.druid.pool.DruidDataSource;import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;/** * 连接池工厂 */public class MyDruidDataSourceFactory extends PooledDataSourceFactory {    public MyDruidDataSourceFactory() {        this.dataSource = new DruidDataSource();        //替换数据源    }}

13.5、修改mybatis-config.xml

mybatis-config.xml中连接池相关配置

<!--连接池--><dataSource type="com.zhang.utils.MyDruidDataSourceFactory">        <!--数据源工厂-->    <!--数据连接参数-->    <property name="driverClass" value="${driver}"/>    <property name="jdbcUrl" value="${url}"/>    <property name="username" value="${username}"/>    <property name="password" value="${password}"/></dataSource>

注:< property name=“属性名” />属性名必须com.alibaba.druid.pool.DruidAbstractDataSource中一致。

14、PageHelper


14.1、什么是PageHelper?

PageHelper是适用于MyBatis框架的一个分页插件,使用方式极为便捷,支持任何复杂的单表、多表分页查询操作。

14.2、访问与下载

官方网站:

下载地址:download

14.3、开发步骤

PageHelper中提供了多个分页操作的静态方法入口。

14.3.1、引入依赖

pom.xml中引入PageHelper依赖

<!--pageHelper分页--><!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --><dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper</artifactId>    <version>5.2.0</version></dependency>

14.3.2、配置mybatis-config.xml

在mybatis-config.xml中添加

<plugins>    <!--com.github.pagehelper为pagehelper类所在包名-->    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin></plugins>

14.3.3、PageHelper应用方式

使用PageHelper提供的静态方法设置分页查询条件

//在查询前,设置分页,查询第一页,每页5条数据//PageHelper 对其之后的第一个功能,进行分页功能追加PageHelper.startPage(1,5);

14.4、PageInfo对象

14.4.1、PageInfo应用方式

使用PageInfo保存分页查询结果

@Testpublic void testPage(){    //在查询前,设置分页,查询第一页,每页5条数据    //PageHelper 对其之后的第一个功能,进行分页功能追加    PageHelper.startPage(1,5);    List<User> users = mapper.queryAllUser();    for (User user : users) {        System.out.println(user);    }    //将查询结果封装到pageInfo对象中    PageInfo<User> pageInfo = new PageInfo<User>(users);    System.out.println(pageInfo);    MybatisUtils.closeSqlSession();}

14.4.2、注意事项

  • 只有在PagetHelperstartPage0方法之后的第一个查询会有执行分页
  • 分页插件**不支持带有"for update"**的查询语句。
  • 分页插件不支持**“嵌套查询**",会导致结果集折叠。所以无法保证分页结果数量正确。。
public class PageInfo<T> extends PageSerializable<T> {
    //当前页
    private int pageNum;		
    //每页的数量
    private int pageSize;
    //当前页的数量
    private int size;
    //当前页面第一个元素在数据库中的行号
    private long startRow;
    //当前页面最后一个元素在数据库中的行号
    private long endRow;
    //总页数
    private int pages;
    //上一页
    private int prePage;
    //下一页
    private int nextPage;
    //是否是第一页
    private boolean isFirstPage;
    //是否是最后一页
    private boolean isLastPage;
    //是否有上一页
    private boolean hasPreviousPage;
    //是否有下一页
    private boolean hasNextPage;
    private int navigatePages;
    private int[] navigatepageNums;
    private int navigateFirstPage;
    private int navigateLastPage;
}

15、$符号的应用场景


${attribute}属于字符串拼接SQL,而非预编译占位符,会有注入攻击问题,不建议在常规SQL中使用,常用于可解决动态升降序问题

15.1、$符号参数绑定

public interface UserDao {
    List<User> queryUsersByUserName(@Param("userName") String userName);
    List<User> queryUsersByIdDesc(@Param("rule")String rule);       //desc  asc
}
<mapper namespace="com.zhang.dao.UserDao">
    <select id="queryUsersByUserName" resultType="user">
        select id, username, pwd, gender
        from mybatis.users
        where username = '${userName}'      <!--拼接userName,如果字符串类型需要用单引号:'${userName}'-->
    </select>

    <select id="queryUsersByIdDesc" resultType="user">
        select id, username, pwd, gender
        from mybatis.users
        order by id ${rule}         <!--拼接desc | asc-->
    </select>
</mapper>
public class TestUserDao {
    @Test
    public void testQueryUsersByIdDesc() {
        UserDao mapper = MybatisUtils.getMapper(UserDao.class);
        List<User> users = mapper.queryUsersByIdDesc("desc");       //调用时传入desc | asc
    }
}

15.2、$符号注入攻击

<mapper namespace="com.zhang.dao.UserDao">
    <select id="queryUsersByUserName" resultType="user">
        select id, username, pwd, gender
        from mybatis.users
        where username = '${userName}'
    </select>		<!--会存在注入攻击,比如传入参数是【String name = "xxx' or '1'='1"】-->
</mapper>
/**
 * #{}:占位符 可以规避sql注入风险
 * 原则:填充数据,要和列相关的位置才能使用
 * select * from users where id = ?
 * insert into users values (?,?,?)
 * update users set username = ?,pwd = ?
 * ${}:存在sql注入问题,随意拼接数据
 */
@Test
public void testInject() {
    UserDao mapper = MybatisUtils.getMapper(UserDao.class);
    List<User> users = mapper.queryUsersByUserName("xxx' or '1'='1");       //由于存在sql注入问题,导致查询结果把全部用户给显示出来
    for (User user : users) {
        System.out.println(user);
    }
}

标签:username,users,gender,mybatis,pwd,Mybatis,id
来源: https://blog.csdn.net/zhang_0202/article/details/118423435

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有