Mybatis简单入门

对着B站动力节点的视频敲的,个人记录一下,感觉入门看这个视频还是够的,但是sql的注解使用,缓存等等都没讲,后续深入学的话可以看刘增辉的《Mybatis从入门到精通》,讲的很好。

一、三层架构

  • 界面层:和用户打交道,接收用户的请求参数,显示处理结果(jsp,html,servlet) controller包

  • 业务逻辑层:接收了界面层传递的数据,计算逻辑,调用数据库,获取数据。 service包

  • 数据访问层:就是访问数据库,执行对数据的查询,修改,删除等等的。 dao包

    三层中类的交互:用户使用界面层–>业务逻辑层–>数据访问层–>数据库

    对应的处理框架:

    • 界面层–servlet–SpringMVC
    • 业务逻辑层–service类–Spring
    • 数据访问层–dao类–Mybatis

框架是一个半成品的软件,定义好了一些基础功能,需要加入自己的功能就是完整的,基础功能是可重复使用的,可升级的。

框架特点:

  • 框架不是全能的,不能做所有的事情
  • 框架是针对某一个领域有效,特长在某一个方面,比如Mybatis做数据库操作,做不了其他的。
  • 框架是一个软件

JDBC的缺陷

  • 代码比较多,开发效率低
  • 需要关注Connection,Statement,ResultSet对象创建和销毁
  • 对ResultSet查询的结果需要自己封装为List
  • 重复的代码太多
  • 业务代码和数据库的操作混在一起

二、Mybatis简单使用

Mybatis是Mybatis SQL Mapper Framework for Java (sql映射框架)

  • sql mapper:可以把数据库中的一行数据,映射为一个java对象,一行数据可以看做是一个java对象,操作这个对象就相当于操作表中的数据
  • Data Access Objects:数据访问,对数据库执行增删改查

Mybatis提供的功能:

  • 提供了创建Connection Statement ResultSet的能力,不用自己创建

  • 提供了执行sql语句的能力,不用自己执行

  • 提供了循环sql,把sql结果转为java对象,封装到List集合

    // 也就是之前写JDBC代码时这个操作
    while(rs.next()) {
        Student student = new Student();
        student.setID(rs.getInt("id"));
        student.setName(rs.getString("name"));
        student.setAge(rs.getInt("age"));
        studentList.add(student);
    }
    
  • 提供了关闭资源的能力,不用自己关闭资源对象

开发人员的工作:提供sql语句

一句话总结:Mybatis是一个sql映射框架,提供数据库的操作能力。

使用步骤

1.新建student表

2.加入mybatis坐标,mysql驱动坐标

3.创建实体类,Student

4.创建持久层的dao接口,定义操作数据库的方法

5.创建一个mybatis映射文件:写sql语句的,一般一个表一个sql映射文件,这个文件是xml文件

​ 1)在接口所在的目录中

​ 2)文件名称和接口保持一致

​ 3)映射文件中namespace的值是dao接口的全限定名

​ 4)映射文件中<select><update>等方法的id必须和接口的方法名一致 (遵循这四条后面才能用mybatis的动态代理)

​ 5)dao接口中不要使用重载方法

6.创建mybatis的主配置文件:一个项目就一个主配置文件。主配置文件提供了数据库的链接信息和sql映射文件的位置信息

7.创建使用mybatis类,通过mybatis访问数据库

  • mybatis映射文件:

    <?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">
    <!--指定约束文件,mybatis-3-mapper.dtd是约束文件的名称,扩展名是dtd的。约束文件是用来限制和检查在当前文件中出现的标签,属性必须符合mybatis的要求。-->
    <mapper namespace="cn.youkee.dao.StudentDao">
        <!--
    		select:表示查询操作
       		id:你要执行的sql语法的唯一标识,mybatis会使用这个id的值来找到要执行的sql语句
    		    可以自定义,但是要求使用接口中的方法名称
    		returnType:表示结果类型的,是sql语句执行后得到的ResultSet,遍历这个ResultSet得到的java对象的类型
    				值写的是类的全限定名称
        -->
        <select id="selectStudents" resultType="cn.youkee.domain.Student">
            select id, name, email, age from student order by id
        </select>
    </mapper>
    <!--mapper是当前文件的根标签,必须的
    	namespace:叫做命名空间,唯一值,可以是自定义的字符串,要求你使用dao接口的全限定名称
    	在当前文件中,可以使用特定的标签,表示数据库的特定操作
    		<select>表示查询
    		<update>表示更新数据库的操作
    		<insert>表示插入
    		<delete>表示删除...-->
    
  • 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文件的位置,从类路径根(maven编译后的target/classes)开始找文件,这里将jdbc.properties放在了resources下,并mark directory as Resource,这样maven编译的时候会直接放在类路径下-->
        <properties resource="jdbc.properties" />
        <!--settings:控制mybatis的全局行为-->
        <settings>
            <!--输出日志到控制台-->
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
        <!--环境配置:数据库的链接信息
    		default:必须和某个environment的id值一样,告诉mybatis使用哪个数据库的连接
    	-->
        <environments default="development">
            <!--environment:一个数据库信息的配置id:一个唯一值,自定义,表示环境的名称-->
            <environment id="development">
                <!--TransactionManager:mybatis的事务类型,Spring里提过,mybatis和JDBC用的一样都是		                          DataSourceTansactionManager
    				type: JDBC(表示使用JDBC中Connection对象的commit,rollback做事务处理)-->
                <transactionManager type="JDBC"/>
                <!--datasource:表示数据源,连接数据库的
    				type:表示数据源的类型,POOLED表示使用连接池-->
                <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>
        <!--sql mapper(sql映射文件)的位置-->
        <mappers>
            <!--一个mapper标签指定一个文件的位置
    			从类路径开始的路径信息
    		-->
            <mapper resource="cn/youkee/dao/StudentDao.xml"/>
            <!--或者可以用package,这个包下的所有xml都会被扫描,但是这个xml文件的名称必须和接口的名称一样(区分大小写),而且在同一个目录之中-->
            <package name="cn.youkee.dao" />
        </mappers>
    </configuration>
    <!--
    	mybatis的主配置文件:主要定义了数据库的配置信息,sql映射文件的位置
    	1.约束文件:
    	<?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">
    	2.configuration 根标签
    -->
    
    

使用mybatis查询数据(很麻烦,后续会简化的)

public class MyApp {
    public static void main(String[] args) throws IOException {
        // 访问mybatis读取student数据
        // 1.定义mybatis主配置文件的名称,从类路径的根开始(target/classes)
        String config = "mybatis.xml";
        // 2.读取这个config表示的文件
        InputStream in = Resources.getResourceAsStream(config);
        // 3.创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        // 4.创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(in);
        // 5.[重要]获取SqlSession对象,从SqlSessionFactory中获取SqlSession
        SqlSession sqlSession = factory.openSession();
        // 6.[重要]指定要执行的sql语句的标识 sql映射文件中的namespace  + "." + 标签的id值
        // 注意如果执行insert,update,delete操作,mybatis默认是不提交事务的
        String sqlID = "cn.youkee.dao.StudentDao" + "." + "selectStudents";
        // sqlSession.commit();
        // 7.执行sql语句,通过sqlID找到语句
        List<Student> studentList = sqlSession.selectList(sqlID);
        // 8.输出结果
        studentList.forEach(student -> System.out.println(student));
        // 9.关闭SqlSession对象
        sqlSession.close();
    }
}

mybatis默认会把JDBC的自动提交事务设为false:Setting autocommit to false on JDBC Connection;最后在关闭sqlSession的时候会再设为true

​ Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2d9d4f9d]
​ Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2d9d4f9d]
​ Returned connection 765284253 to pool.

Mybatis主要类的介绍

  • Resources:Mybatis中的一个类,负责读取主配置文件

    String config = "mybatis.xml";
    InputStream in = Resources.getResourceAsStream(config);
    
  • SqlSessionFactoryBuilder:创建SqlSessionFactory对象

    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(in);
    
  • SqlSessionFactory:重量级对象,程序创建一个对象耗时比较长,使用资源比较多。整个项目中有一个就够了。本身是个接口,接口的实现类是DefaultSqlSessionFactory。主要是为了获得SqlSession对象。

    SqlSession sqlSession = factory.openSession();
    

    openSession()方法说明:

    • openSession()无参的,获取非自动提交事务的SqlSession对象
    • openSession(true),获取自动提交事务的对象,false就非自动提交的
  • SqlSession:接口,定义了操作数据的方法,例如:selectOne(), selectList(), insert(), commit(), rollback()。实现类是DefaultSqlSession。

    使用要求:SqlSession对象不是线程安全的,需要在方法内部使用,在执行sql语句之前,使用openSession()获取SqlSession对象,在执行完sql语句自后,需要关闭它,执行SqlSession.clos()。这样能保证他的使用时线程安全的。

三、Mybatis核心功能

使用Mybatis的动态代理

上述只有SqlSession是每次数据库操作都需要的,可以写个工具类获取,然后用完后自己关了。

public class MybatisUtils {
    private static SqlSessionFactory factory;
    static {
        String config = "mybatis.xml";
        try {
            InputStream in = Resources.getResourceAsStream(config);
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 获取SqlSession的方法
    public static SqlSession getSqlSession() {
        SqlSession sqlSession = null;
        if (factory != null) {
            sqlSession = factory.openSession();
        }

        return sqlSession;
    }
}

那么这个时候的代码就可以改为:

public interface StudentDao {
    List<Student> selectStudents();

    int insertStudent(Student  student);
}

public class StudentDaoImpl implements StudentDao {
    @Override
    public int insertStudent(Student student) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        String sqlID = "cn.youkee.dao.StudentDao.insertStudent";
        int ret = sqlSession.insert(sqlID, student);
        sqlSession.commit();
        sqlSession.close();
        return ret;
    }

    @Override
    public List<Student> selectStudents() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        String sqlID = "cn.youkee.dao.StudentDao.selectStudents";
        List<Student> students = sqlSession.selectList(sqlID);
        sqlSession.close();
        return students;
    }
}

这个时候,假如我们需要在业务层调用某个DAO方法,那么代码就是这样的:

public void queryService() {
    /*
    	List<Student> studentList = studentDao.selectStudents();
    	这行代码中:
    	1.dao对象的类型是StudentDao,全限定名是cn.youkee.dao.StudentDao,这里和上面配置的namespace是一样的
    	2.方法selectStudents()和mapper文件中的id值selectStudents是一样的
        3.等于说只要调用这个方法,就可以自动把上面的sqlID拼出来,而且根据mapper的配置,还可以知道到底执行的是select操作还           是insert操作,还可以根据dao方法的返回值确定是不是selectList。
        
        mybatis动态代理:mybatis根据dao的方法调用,获取执行sql语句的信息。mybatis根据你的dao接口,创建出一个dao
        的实现类,并创建这个类的对象,完成SqlSession调用方法,访问数据库。也就是说自己连DAOImpl都不用写了。
        用的是jdk的动态代理,也就是需要接口的。
    */
    StudentDao studentDao = new StudentDaoImpl();
    List<Student> studentList = studentDao.selectStudents();
    studentList.forEach(System.out::println);
}
public void TestSelectStudents() {
	/*
		使用Mybatis的动态代理机制,使用SqlSession.getMapper(dao接口)
		getMapper能获取dao接口对应的实现类对象
	*/ 
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    List<Student> studentList = dao.selectStudents();
    studentList.forEach(System.out::println);
    sqlSession.close();
}

传入参数

从java代码中把数据传入到mapper文件的sql语句中(比如where中的条件)

  • parameterType:mapper文件中的一个属性,表示dao接口中方法的参数的数据类型,例如StudentDao接口中有一个根据Id获取学生的方法

    // 一个简单类型的参数。mybatis把基本类型数据和String都叫简单类型
    public Student selectStudentById(Integer id);
    
  
那么需要在mapper文件中配置
  
  ```xml
  <select id="selectStudentById" resultType="cn.youkee.domain.Student" parameterType="java.lang.Integer">
          select id, name, email, age from student where id = #{id}
  </select>
  <!--
  	parameterType:dao接口中方法参数的数据类型,它的值是java数据类型全限定名称或者mybatis定义的别名
  	注意:parameterType不是强制的,mybatis通过反射机制能够发现接口参数的类型,所以可以没有
	#{}只是占位符,括号里的内容是任意的,方便区分就可以。mybatis执行的是jdbc中的PreparedStatement对象
	由mybatis执行下面的代码:
		1.mybatis创建Connection,PreparedStatement
		String sql = “select id, name, email, age from student where id = ?”
		PreparedStatement pst = conn.prepareStetement(sql);
		pst.setInt(1, 1001);
		2.执行sql封装为resultType="cn.youkee.domain.Student"这个对象
		ResultSet rs = rs.executeQuery();
		while(rs.next()) {
			Student student = new Student();
			student.setId(re.getInt("Id"));
			...
		}
		return student;// 赋給了dao方法调用的返回值
  -->

然后用的时候直接调方法就行了。

下面是mybatis定义的别名,这样就不用写全限定名。

  • @Param命名参数,传多个参数

    比如:

    public List<Student> selectMutiParam(@Param("myName") String name, @Param("myAge") Integer age);
    

    那么mapper文件中就需要这么配置:

    <select id="selectMultiParam" resultType="cn.youkee.domain.Student">
    	select * from student where name=#{myName} or age=#{myAge}
    </select>
    
  • 传入一个对象

    定义一个cn.youkee.vo.QueryParam.java对象

    public class QueryParam {
        private String paramName;
        private Integer paramAge;
        ...
    }
    

    然后再StudentDao中定义一个方法

    List<Student> selectMultiObject(QueryParam param);
    

    mapper中就需要这么定义

    <!--
    	使用对象的语法:#{属性名,javaType=类型名称,jdbcType=数据类型},这是完整的语法,很少用
    		javaType:值java中的属性数据类型,jdbcType:在数据库中的数据类型
     		例如:#{paraName, javaType=java.lang.String, jdbcType=VARCHAR}
    	使用简化的就可以,只传属性名就ok,javaType和jdbcType会自动获取
    -->
    <select id="selectMultiParam" resultType="cn.youkee.domain.Student">
    	select * from student where name=#{paramName} or age=#{paramAge}
    </select>
    

    其实未必要单独写一个QueryParam对象,用之前的Student对象就可以。只需要把这个Student对象对应的属性设置为你想查询的值就可以,别的属性的值(比如这个例子里的Id和email)可以不设置,就不单独写了。

  • 按位置传递参数,这个了解就可以,不常用

    比如还是上面的例子需要传name和age,这时mapper文件里的占位符用#{arg0}和#{arg1}分别对应这两个参数。(mybatis 3.4之前是#{0}和#{1})。

  • 使用Map传递参数,这个也不常用

    Map<String, Object> map = new HashMap<>();
    map.put("myName", "张三");
    map.put("myAge", 20);
    

    那么mapper文件中的占位符还是用#{myName}和#{myAge}就可以了。接口中的方法参数也是Map,**可读性太差了,单看接口啥都看不出来。**阿里巴巴开发手册也禁止用map当参数。

  • #和$的区别

    #用的是占位符,对应PreparedStatement,所以#{id}执行的sql语句是

    select * from student where id = ?;
    

    $用的是sql拼接,对应Statement对象,有sql注入的风险,并且执行的效率也低,执行${id}的结果是

    select * from student where id = 1001; // 1001是查询的时候传的参数
    

    但是$ 可以用来替换列名或表名,比如oder by ${colName}

Mybatis的输出结果

mybatis执行了sql语句,得到java对象。

  • resultType:结果类型,指sql语句执行完毕后,数据转为的java对象。之前的select标签里就配过,是方法结果得到对象的全限定名(或者上面表里的别名)。

    这个对象可以是java基础类,也可以是数据库表对应的实体类,也可以是根据查询需要定义的新的类(比如多表查询的结果)。

    处理方式:

    • mybatis执行sql语句,然后调用类的无参数构造方法,创建对象
    • mybatis把ResultSet指定列值赋给同名的属性 (jdbc对应的做法上面写过了就不写了)

    1.实体对象也可以定义别名,需要在mybatis.xml中配置typeAlias,然后resultType就可以用别名stu(不建议)

    2.或者把domain包给配进去,这样写resultType的时候就不用写前面的包名,直接写Student就可以(也不是很建议,如果多个包下的类名相同,就没办法区分了)

    最建议的还是用全限定名

    <typeAliases>
    	1.<typeAlias type="cn.youkee.domain.Student" alias="stu" />
        2.<package name="cn.youkee.domain" />
    </typeAliases>
    

    resultType还可以是Map的,key对应列名,value对应列值,但是因为key不可重复,所以只能返回一行数据,没啥实际意义。

  • resultMap:结果映射,指定列名和java对象的属性对应关系,上面讲的都是列名和属性名一样,然后mybatis直接赋值。

    但是当列名和属性名不一样时,一定要用resultMap,定义列值赋值给哪个属性万一数据库的列名和自己定义的属性名不一样,这个就派上用场了(在实际开发中很常见)。在映射文件中应该这么配置:

    <!--现在假设数据库的列名和java对象的属性名都不一样。id是自定义名称,用来引用这个resultMap,type是java类型的全限定名-->
    <resultlMap id="studentMap" type="cn.youkee.domain.Student">
        <!--主键列,使用id。column对应数据库表的列名,property对应java对象的属性名-->
    	<id column="id" property="StuId" />
        <!--非主键列,使用result-->
        <result column="name" property="StuName" />
        <result column="email" property="StuEmail" />
        <result column="age" property="StuAge" />
    </resultlMap>
    <select id="selectAllStudents" resultMap="studentMap">
    	select id, name, email, age from  student
    </select>
    

    resultType和resultMap二者不能同时用!!!resultMap里已经指定了类的全限定名了

    还有一种解决办法就是select的时候把列名都给起个别名,比如select id as StuId, name as StuName… 这样不配resultMap也可以,用resultType就可以一一对应了。因为resultType的默认原则就是同名列值赋给同名属性。

模糊查询

  • 第一种方法,java代码指定like的内容

    <select id="selectLikeOne" resultType="cn.youkee.domain.Student">
    	select id, name, email, age from  student where name like #{namae}
    </select>
    
    List<Student> list = dao.selectLikeOne("%李%");
    
  • 第二种方式,在mapper文件中拼接。这个时候java传的就是"李",需要在mapper中拼 %,mapper中name前后的空格都必须有。而且这个时候如果只需要一个%的话就需要改mapper文件,不灵活。

    <select id="selectLikeTwo" resultType="cn.youkee.domain.Student">
    	select id, name, email, age from  student where name like "%" #{namae} "%"
    </select>
    
    List<Student> list = dao.selectLikeOne("李");
    

四、动态SQL

动态sql:sql语句是变化的,可以根据条件获取到不同的sql语句。主要是where部分发生变化。

动态sql的实现,使用的是mybatis提供的标签<if> <where><foreach>。动态sql要使用java对象作为参数。

<if>

<if>是判断条件的,语法是:

<if test="判断java对象的属性值">
	sql
</if>
<select id="selectStudentIf" resultType="cn.youkee.domain.Student">
        select * from student
        where
        <if test="name != null and name != ''">
            name = #{name}
        </if>
        <if test="age > 0">
            or age > #{age}
        </if>
    </select>
List<Student> selectStudentIf(Student student);

但是如果name的test不通过,age的test通过,这个时候就会多出来or,会报语法错误,所以单独使用意义不是很大。需要结合别的标签一块用。

<where>

<where>用来包含多个<if>,当多个if有一个成立的,<where>会自动增加一个where关键字,并去掉if中多余的and 、or等,写法如下:

<select id="selectStudentWhere" resultType="cn.youkee.domain.Student">
    select * from student
    <where>
        <if test="name != null">
            name = #{name}
        </if>
        <if test="age > 0">
            or age > #{age}
        </if>
    </where>
</select>

<foreach>

<foreach>循环java中的数组,List集合的,主要是用在sql的in语句,比如:

select * from student where id in (1001, 1002, 1003);

foreach的语法如下:

<foreach collection="" item="" open="" close="" separator=""></foreach>
<!--
	collection:表示接口中的方法参数的类型,如果是数组使用array,如果是list集合使用list
	item:自定义的,表示数组或集合成员的变量
	open:循环开始时的字符
	close:循环结束时的字符
	separator:集合成员之间的分隔符
-->
  1. 简单类型的List

    具体配置应该这么配:

    List<Student> selectForeachOne(List<Integer> idList);
    
    <select id="selectForeachOne" resultType="cn.youkee.domain.Student">
        select  * from student where id in
        <foreach collection="list" item="myid" open="(" close=")" separator=",">
            #{myid}
        </foreach>
    </select>
    

    测试方法如下:

    @Test
    public void TestForeachOne() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Integer> list = new ArrayList<>(Arrays.asList(1001, 1002, 1003));
        List<Student> studentList = dao.selectForeachOne(list);
        studentList.forEach(System.out::println);
        sqlSession.close();
    }
    

    通过控制台日志,可以看到执行的sql语句为:

    Preparing: select * from student where id in ( ? , ? , ? )
    Parameters: 1001(Integer), 1002(Integer), 1003(Integer)
    Columns: id, name, email, age
    Row: 1001, 李四, lisi@qq.com, 20
    Row: 1002, 张三, zhangsan@gmail.com, 21
    Row: 1003, 张飞, zhangfei@foxmail.com, 26
    Total: 3

  2. 自定义对象的List

    List<Student> selectForeachTwo(List<Student> stuList);
    
    <select id="selectForeachTwo" resultType="cn.youkee.domain.Student">
        select  * from student where id in
        <foreach collection="list" item="stu" open="(" close=")" separator=",">
            #{stu.id}  相当于调用stu.getId()
        </foreach>
    </select>
    

代码片段

复用一些sql语句

<sql id="selectStudent">
	select * from student
</sql>
<select id="..." resultType="...">
	<include refid="selectStudent"/> where
    ...
</select>

五、PageHelper

PageHelper用来做数据分页的,非常重要,后面用数据库离不开分页!

maven引入依赖之后,需要在mybatis主配置文件<environment>标签之前加上插件的配置

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="reasonable" value="true"/>
    </plugin>
</plugins>

代码中用起来非常方便

@Test
public void TestSelectAllStudents() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    // 第一个参数:pageNum,第几页,从1开始
    // 第二个参数:pageSize,一页中几行数据
    PageHelper.startPage(2, 2);
    List<Student> studentList = dao.selectAllStudents();
    studentList.forEach(System.out::println);
    sqlSession.close();
}

通过看控制台日志,会发现他先会查询数据库,看一共有多少行数据:

Preparing: SELECT count(0) FROM student
Parameters:
Columns: count(0)
Row: 5
Total: 1

然后再执行查询的sql语句:

Preparing: select * from student order by id LIMIT ?, ?
Parameters: 2(Integer), 2(Integer)
Columns: id, name, email, age
Row: 1003, 张飞, zhangfei@foxmail.com, 26
Row: 1004, 刘备, liubei@163.com, 22
Total: 2

这里规则就和sql的一样了,从第2条数据开始,取2条。相当于不用自己去计算从第几条开始了,只需要指定页数就行了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值