1. 软件开发常用结构

1.1 三层架构

  1. 界面层(表示层,视图层):主要功能是接受用户的数据,显示请求的处理结果。使用 web 页面和用户交互,手机 app 也就是表示层的,用户在 app 中操作,业务逻辑在服务器端处理。
  2. 业务逻辑层:接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
  3. 数据访问层:与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库.

三层的处理请求的交互:

用户—> 界面层—>业务逻辑层—>数据访问层—>DB 数据库

resultmap进行类型转换_resultmap进行类型转换


为什么要使用三层?

1,结构清晰、耦合度低, 各层分工明确

2,可维护性高,可扩展性高

3,有利于标准化

4,开发人员可以只关注整个结构中的其中某一层的功能实现

5,有利于各层逻辑的复用

三层对应的处理框架

  • 界面层—servlet—springmvc(框架)
  • 业务逻辑层—service类–spring(框架)
  • 数据访问层—dao类–mybatis(框架)

2. MyBatis框架介绍

2.1 MyBatis 解决的主要问题

  • 传统JDBC编程存在的问题
  • 代码比较多,开发效率低
  • 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
  • 对 ResultSet 查询的结果,需要自己封装为 List
  • 重复的代码比较多些
  • 业务代码和数据库的操作混在一起
public void findStudent() {
	 Connection conn = null;
	 Statement stmt = null;
	 ResultSet rs = null;
	 try {
		 //注册 mysql 驱动
		 Class.forName("com.mysql.jdbc.Driver");
		 //连接数据的基本信息 url ,username,password
		 String url = "jdbc:mysql://localhost:3306/springdb";
		 String username = "root";
		 String password = "123456";
		 //创建连接对象
		 conn = DriverManager.getConnection(url, username, password);
		 //保存查询结果
		 List<Student> stuList = new ArrayList<>();
		 //创建 Statement, 用来执行 sql 语句
		 stmt = conn.createStatement();
		 //执行查询,创建记录集,
		 rs = stmt.executeQuery("select * from student");
		 while (rs.next()) {
			 Student stu = new Student();
			 stu.setId(rs.getInt("id"));
			 stu.setName(rs.getString("name"));
			 stu.setAge(rs.getInt("age"));
			 //从数据库取出数据转为 Student 对象,封装到 List 集合
			 stuList.add(stu);
	 }
	
	 } catch (Exception e) {
	 	e.printStackTrace();
	 } finally {
		 try {
		 //关闭资源
			 if (rs != null) ;
			 {
			 	rs.close();
			 }
			 if (stmt != null) {
			 	stmt.close();
			 }
			 if (conn != null) {
			 	conn.close();
			 }
	 } catch (Exception e) {
	 	e.printStackTrace();
	 	}
	} 
}
  • MyBatis 解决的主要问题

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

MyBatis 可以完成:
1. 注册数据库的驱动,例如 Class.forName(“com.mysql.jdbc.Driver”))
2. 创建 JDBC 中必须使用的 Connection , Statement, ResultSet 对象
3. 从 xml 中获取 sql,并执行 sql 语句,把 ResultSet 结果转换 java 对象
	List<Student> list = new ArrayLsit<>();
	ResultSet rs = state.executeQuery(“select * from student”);
	while(rs.next){
	 Student student = new Student();
	 student.setName(rs.getString(“name”));
	 student.setAge(rs.getInt(“age”));
	 list.add(student);
	}
4.关闭资源
	ResultSet.close() , Statement.close() , Conenection.close()

2.2 IDEA中如何使用MyBatis

MyBatis入门案例

  1. 第一步: 创建 mysql 数据库和表
    数据库名 ssm ;表名 student
  2. resultmap进行类型转换_resultmap进行类型转换_02

  3. 第二步:创建 maven 工程
  4. resultmap进行类型转换_mysql_03

  5. 第三步:在Pom文件加入 MyBatis依赖和数据库驱动依赖
<!--mybatis依赖 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--mysql驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.23</version>
    </dependency>
  </dependencies>
  1. 第四步:编写 Student 实体类
    创建包 com.bjpowernode.entity, 包中创建 Student 类
package com.bjpowernode.entity;
//实体类推荐和表名一样
public class Student {
    //定义属性,目前要求是属性名和列名一样
    private Integer id;
    private String name;
    private String email;
    private Integer age;
    public Student(){}
    public Student(Integer id, String name, String email, Integer age) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}
  1. 第五步:编写 Dao 接口 StudentDao
    创建 com.bjpowernode.dao 包,创建 StudentDao 接口
package com.bjpowernode.dao;	
import com.bjpowernode.entity.Student;	
import java.util.List;	
//接口操作student表
public interface StudentDao {
    //查询student表的所有数据
    public List<Student> selectStudents();

    //插入方法

    /**
     *
     * @param student:插入数据库中的数据
     * @return int:表示执行insert操作后,影响数据库中的行数
     */
    public int insertStudents(Student student);
}
  1. 第六步:编写 Dao 接口 Mapper 映射文件 StudentDao.xml
    要求:
  1. 在 dao 包中创建文件 StudentDao.xml
  2. 要求 StudentDao.xml 文件名称和接口 StudentDao 一样,区分大小写的一样。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.StudentDao">
    <!--
        select:表示查询操作
        id:你要执行sql语句的唯一标识,mybatis会使用这个id的值找到要执行的sql语句
            可以自定义,但是要求你要求你使用接口中的方法名称。
        resultType:表示结果类型的,是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型。
            值写的是类型的全限定名称。
    -->
    <select id="selectStudents" resultType="com.bjpowernode.entity.Student">
        select id,name,email,age from student
    </select>
    <!--插入操作-->
    <insert id="insertStudents">
        insert into student values(#{id},#{name},#{email},#{age})
    </insert>
</mapper>

<!--
    sql映射文件:写sql语句,mybatis会执行这些sql

    1. 指定约束文件
        <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

        mybatis-3-mapper.dtd:是约束文件,扩展名是dtd的
    2. 约束文件的作用:限制和检查在当前文件中出现的标签,属性必须符合mybatis的要求

    3. mapper是当前文件的根标签,必须的
       namespace 是命名空间,唯一值的,可以是自定义的字符串,要求你使用dao接口的全限定名称.

    4. 在当前文件中可以使用特点的标签,表示数据库的特定操作
        <select>:表示执行查询
        <update>:表示更新数据库的操作,就是在<update>标签中写的是update sql语句
        <insert>:表示插入
        <delete>:表示的是删除
-->
  1. 第七步:创建 MyBatis 主配置文件
    项目 src/main 下创建 resources 目录,设置 resources 目录为 resources root
    创建主配置文件:名称为 mybatis.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>
    <!--settings:控制mybatis全局行为的-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    <!--环境配置:数据库的连接信息
        default : 必须和某个environment中的id值一样
        告诉mybatis即将连接的是哪个数据库的的连接信息,也就是访问哪个数据库
        (这里的不同不是数据库产品的不同,而是在不同项目运行状态下使用的数据库不用)
            如:在线上和本地使用的数据库不同,
    -->
    <environments default="mydev">
        <!--environment:一个数据库信息的配置,环境
            id:一个唯一值,自定义的,表示环境的名称
        -->
        <environment id="mydev">
            <!--transactionManager:mybatis的事务类型
                type:JDBC(表示使用jdbc中的connection对象的commit,rollback做事务处理)-->
            <transactionManager type="JDBC"/>
            <!--dataSource:表示数据源,连接数据库的
                type:表示数据源的类型,POOLED表示使用的连接池
            -->
            <dataSource type="POOLED">
                <!--
                    driver,url,username,password 是固定的们不能自定义
                -->
                <!--driver,数据库驱动类名-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--url,数据库连接地址-->
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <!--username,连接数据库的用户名称-->
                <property name="username" value="root"/>
                <!--password,连接数据库的用户的密码-->
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--sql映射文件的地址-->
    <mappers>
        <!--一个mapper标签指定一个文件的位置
            从类路径开始的路径信息
        -->
        <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
    </mappers>
</configuration>
<!--
    mybatis的主配置文件:主要定义了数据库的配置信息,sql映射文件的位置


    1. 约束文件
        <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    2. 根标签:<configuration>
-->
  1. 创建测试类
package com.bjpowernode;

import com.bjpowernode.entity.Student;
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;
import java.util.List;

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值
        String sqlId = "com.bjpowernode.dao.StudentDao" + "." + "selectStudents";
        // 7.执行sql语句,通过sqlId找到语句
        List<Student> studentList = sqlSession.selectList(sqlId);

        // 8.输出结果
        for (Student stu:studentList) {
            System.out.println(stu);
        }
        // 9.关闭SqlSession对象
        sqlSession.close();
    }
}

2.3 主要类的介绍

  • Resources: mybatis中的一个类, 负责读取主配置文件
    InputStream in = Resources.getResourceAsStream(“mybatis.xml”);
  • SqlSessionFactoryBuilder : 创建SqlSessionFactory对象,
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    //创建SqlSessionFactory对象
    SqlSessionFactory factory = builder.build(in);
  • SqlSessionFactory : 重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。
在整个项目中,有一个就够用了。
   SqlSessionFactory:接口  , 接口实现类: DefaultSqlSessionFactory
   SqlSessionFactory作用: 获取SqlSession对象。SqlSession sqlSession = factory.openSession();

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

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

3. MyBatis框架Dao代理

小便捷:创建MyBatis的util工具类封装一下部分类的使用

package com.bjpowernode.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;

public class MyBatisUtils {
    private static SqlSessionFactory factory = null;
    static {
        //读取mybatis主配置文件
        String config = "mybatis.xml";//需要和你的项目中名字一样
        try {
            InputStream in = Resources.getResourceAsStream(config);
            //创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
             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;
    }
}

3.1 Dao 代理实现 CURD

(1) 去掉 Dao 接口实现类

resultmap进行类型转换_mybatis_04

(2) getMapper 获取代理对象
只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定 Dao接口类的 class 值。

package com.bjpowernode;

import com.bjpowernode.dao.StudentDao;
import com.bjpowernode.entity.Student;
import com.bjpowernode.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class TestMyBatis {
    @Test
    public void testSelectStudents(){
        /**
         * 使用MyBatis的动态代理机制,使用sqlSession,getMapper(dao接口)
         * getMapper能够获取的是dao接口的实现类对象
         */
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        //调用dao的方法执行数据库的操作
        List<Student> studentList = dao.selectStudents();
        for (Student stu:studentList) {
            System.out.println(stu);
        }
    }
    @Test
    public void testInsertStudents(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();

        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        //调用dao的方法执行数据库的操作
        int nums = dao.insertStudents(new Student(1005, "刘备", "liubei@163.com", 25));
        sqlSession.commit();
        System.out.println("添加成员" + nums);
    }
}

3.2 深入理解参数

3.2.1 parameterType

parameterType: 接口中方法参数的类型, 类型的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从 java 代码传入到mapper 文件的 sql 语句。

例如:

<delete id="deleteStudent" parameterType="int">
	 delete from student where id=#{studentId}
</delete>

等同于

<delete id="deleteStudent" parameterType="java.lang.Integer">
	 delete from student where id=#{studentId}
</delete>

如:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.StudentDao">
    <!--
        parameterType : dao接口中方法参数的数据类型
        parameterType的值是java数据类型全限定名称或者是mybatis定义的别名
        例如:parameterType="java.lang.Integer"
           或    parameterType="int"
        注意:parameterType不是强制的,mybatis可以通过反射机制发现接口中的参数的数据类型
            所以可以没有,一般不写。
     -->
    <select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.bjpowernode.entity.Student">
        select id,name,email,age from student where id = #{id}
    </select>
</mapper>

3.2.2 MyBatis 传递参数

  • 一个简单类型的参数:
简单类型: mybatis把java的基本数据类型和String都叫简单类型。
 在mapper文件获取简单类型的一个参数的值,使用 #{任意字符}

 接口:public Student  selectStudentById(Integer id) 
 mapper:select id,name, email,age from student where id=#{studentId}
  • 多个参数,使用@Param命名参数
接口 public List<Student> selectMulitParam(@Param("myname") String name, @Param("myage") Integer age)
   使用  @Param("参数名")  String name 
 mapper文件:
      <select>
          select * from student where name=#{myname} or age=#{myage}
 	  </select>
  • 多个参数,使用java对象
    语法 #{属性名}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.StudentDao">
    <select id="selectStudentById" parameterType="int" resultType="com.bjpowernode.domain.Student">
        select id,name, email,age from student where id=${studentId}
    </select>

    <!--多个参数,使用@Param命名-->
    <select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
         select id,name, email,age from student where name=#{myname} or age=#{myage}
    </select>

    <!--多个参数, 使用java对象的属性值,作为参数实际值
        使用对象语法: #{属性名,javaType=类型名称,jdbcType=数据类型} 很少用。
                    javaType:指java中的属性数据类型。
                    jdbcType:在数据库中的数据类型。
                    例如: #{paramName,javaType=java.lang.String,jdbcType=VARCHAR}

        我们使用的简化方式: #{属性名}  ,javaType, jdbcType的值mybatis反射能获取。不用提供

    -->
   <!-- <select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
          select id,name, email,age from student where
           name=#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
           or age=#{paramAge,javaType=java.lang.Integer,jdbcType=INTEGER}
    </select>-->

    <select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
          select id,name, email,age from student where
           name=#{paramName}   or age=#{paramAge}
    </select>

    <select id="selectMultiStudent" resultType="com.bjpowernode.domain.Student">
         select id,name, email,age from student where name=#{name} or age=#{age}
    </select>

    <!--多个参数使用位置-->
    <select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
          select id,name, email,age from student where
          name = #{arg0} or age=#{arg1}
    </select>

    <!--多个参数,使用Map , 使用语法 #{map的key}-->
    <select id="selectMultiByMap" resultType="com.bjpowernode.domain.Student">
          select id,name, email,age from student where
          name = #{myname} or age=#{age1}
    </select>

    <!--使用 ${}-->
    <select id="selectUse$" resultType="com.bjpowernode.domain.Student">
         select * from student where name=${myname}
    </select>

    <!--
       $替换列名
    -->
    <select id="selectUse$Order" resultType="com.bjpowernode.domain.Student">
         select * from student order by ${colName}
    </select>
</mapper>
package com.bjpowernode.dao;

import com.bjpowernode.domain.Student;
import com.bjpowernode.vo.QueryParam;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface StudentDao {

    /**
     * 一个简单类型的参数:
     *   简单类型: mybatis把java的基本数据类型和String都叫简单类型。
     *  在mapper文件获取简单类型的一个参数的值,使用 #{任意字符}
     */
    public Student selectStudentById(@Param("studentId") Integer id);

    /**
     * 多个参数: 命名参数,在形参定义的前面加入 @Param("自定义参数名称")
     */
    List<Student> selectMultiParam(@Param("myname") String name,
                                   @Param("myage") Integer age);


    /**
     * 多个参数,使用java对象作为接口中方法的参数
     */
    List<Student> selectMultiObject(QueryParam param);

    List<Student> selectMultiStudent(Student student);

    /**
     * 多个参数-简单类型的,按位置传值,
     * mybatis.3.4之前,使用 #{0} ,#{1}
     * mybatis。3.4之后 ,使用 #{arg0} ,#{arg1}
     */
    List<Student> selectMultiPosition( String name,Integer age);

    /**
     * 多个参数,使用Map存放多个值
     */
    List<Student> selectMultiByMap(Map<String,Object> map);



    List<Student> selectUse$(@Param("myname") String name);

    List<Student> selectUse$Order(@Param("colName") String colName);
}

3.2.3 # 和 $

select id,name, email,age from student where id=#{studentId}

# 的结果: select id,name, email,age from student where id=?

select id,name, email,age from student where id=${studentId}

$ 的结果:select id,name, email,age from student where id=1001
  • .# 和 $区别
  1. #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
  2. #能够避免sql注入,更安全。
  3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
  4. $有sql注入的风险,缺乏安全性。

3.2.4 resultMap和resultType 及模糊查询Like

1)resultType结果类型, 指sql语句执行完毕后, 数据转为的java对象, java类型是任意的。
   resultType结果类型的它值 
   	1. 类型的全限定名称   2. 类型的别名, 例如 java.lang.Integer别名是int


    处理方式:
	   1. mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象。
	   2. mybatis把ResultSet指定列值付给同名的属性。


		<select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
     		 select id,name, email,age from student
  	    </select>

	  对等的jdbc
	  ResultSet rs = executeQuery(" select id,name, email,age from student" )
	  while(rs.next()){
           Student  student = new Student();
				student.setId(rs.getInt("id"));
				student.setName(rs.getString("name"))
	  }

2)  定义自定义类型的别名
	    1)在mybatis主配置文件中定义,使<typeAlias>定义别名
		2)可以在resultType中使用自定义别名
3)resultMap:结果映射, 指定列名和java对象的属性对应关系。
	    1)你自定义列值赋值给哪个属性
		 2)当你的列名和属性名不一样时,一定使用resultMap
	 resultMap和resultType不要一起用,二选一
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.StudentDao">

    <!--selectStudentReturnViewStudent-->
    <select id="selectStudentReturnViewStudent" resultType="ViewStudent">
        select id,name  from student where id=#{sid}
    </select>


    <!--sql执行后返回一行一列-->
    <!--<select id="countStudent" resultType="int">-->
    <select id="countStudent" resultType="java.lang.Integer">
        select count(*) from student
    </select>

    <!--返回Map
        1)列名是map的key, 列值是map的value
        2)只能最多返回一行记录。多余一行是错误
    -->
    <select id="selectMapById" resultType="java.util.HashMap">
        select id,name,email from student where id=#{stuid}
    </select>

    <!--使用resultMap
        1)先定义resultMap
        2)在select标签,使用resultMap来引用1定义的。
    -->

    <!--定义resultMap
        id:自定义名称,表示你定义的这个resultMap
        type:java类型的全限定名称
    -->
    <resultMap id="studentMap" type="com.bjpowernode.domain.Student">
        <!--列名和java属性的关系-->
        <!--注解列,使用id标签
            column :列名
            property:java类型的属性名
        -->
        <id column="id" property="id" />
        <!--非主键列,使用result-->
        <result column="name" property="name" />
        <result column="email" property="email" />
        <result column="age" property="age" />

    </resultMap>
    <select id="selectAllStudents" resultMap="studentMap">
        select id,name, email , age from student
    </select>


    <resultMap id="myStudentMap" type="com.bjpowernode.domain.MyStudent">
        <!--列名和java属性的关系-->

        <id column="id" property="stuid" />
        <!--非主键列,使用result-->
        <result column="name" property="stuname" />
        <result column="email" property="stuemail" />
        <result column="age" property="stuage" />

    </resultMap>
    <!--列名和属性名不一样:第一种方式-->
    <select id="selectMyStudent" resultMap="myStudentMap">

         select id,name, email , age from student
    </select>

    <!--列名和属性名不一样:第二种方式
       resultType的默认原则是 同名的列值赋值给同名的属性, 使用列别名(java对象的属性名)
    -->
    <select id="selectDiffColProperty" resultType="com.bjpowernode.domain.MyStudent">
        select id as stuid ,name as stuname, email as stuemail , age stuage from student
    </select>


    <!--第一种 like , java代码指定 like的内容-->
    <select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student where name like #{name}
    </select>

    <!--第二种方式:在mapper文件中拼接 like的内容-->
    <select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student where name  like "%" #{name} "%"
    </select>
</mapper>

4. 动态sql

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

动态sql的实现

使用的是mybatis提供的标签, <if> ,<where>,<foreach>

4.1 if 标签使用

<!--if
         <if test = "使用参数java对象的属性值作为判断条件  语法规则:属性名 = xxx值"
    -->
    <select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
        <include refid="studentSql"/>
        where
        <if test="name != null and name != ''">
            name = #{name}
        </if>
        <if test="age > 0">
            or age > #{age}
        </if>
    </select>

缺点:当使用多个if标签命令时,会产生SQL语法错误。如下所示:

<sql id="studentSql">
    select id,name,email,age from student
</sql>
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
        <include refid="studentSql"/>
        where
        <if test="name != null and name != ''">
            name = #{name}
        </if>
        <if test="age > 0">
            or age > #{age}
        </if>
 </select>
 在输入参数时:若判断name时不符合条件,而age符合条件,此时的sql语句会变为:
	 select id,name,email,age from student or age = ?
此时存在语法错误。

解决方法:
法1 : 如下所示
缺陷:在实际情况中,若后面两个条件都不符合时会使用 1 = 1查询到所有数据,但是sql原意是查询不到数据。

<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
	        <include refid="studentSql"/>
	        where
	        1 = 1
	        <if test="name != null and name != ''">
	          and  name = #{name}
	        </if>
	        <if test="age > 0">
	            or age > #{age}
	        </if>
	 </select>

法2 : 使用where标签,不存在上述缺陷

4.2 where 标签使用

用来包含 多个if的, 当多个if有一个成立的, where会自动增加一个where关键字,并去掉 if中多余的 and ,or等。

<!--where : <where> <if> </if>... </where>
    -->
    
    <select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
        <include refid="studentSql"/>
        <where>
            <if test="name != null and name != ''">
                name = #{name}
            </if>
            <if test="age > 0">
                or age > #{age}
            </if>
        </where>
    </select>

4.3 foreach 标签使用

foreach 标签用于实现对于数组与集合的遍历。对其使用,需要注意:
➢ collection 表示要遍历的集合类型, list ,array 等。
➢ open、close、separator 为对遍历内容的 SQL 拼接。

语法:
<foreach collection="集合类型" open="开始的字符" close="结束的字符" 
item="集合中的成员" separator="集合成员之间的分隔符">
 #{item 的值}
</foreach>
<!--foreach使用1  ,当传入的List集合中存储的是基本数据类型时
    -->
    <select id="selectStudentOne" resultType="com.bjpowernode.domain.Student">
        <include refid="studentSql"/>  where id in
        <foreach collection="list" item="myid" open="(" close=")" separator=",">
            #{myid}
        </foreach>
    </select>

    <!--foreach使用2   当传入的List集合中存储的是引用数据类型时,直接使用引用.属性名 的方式。
 -->
    <select id="selectStudentTwo" resultType="com.bjpowernode.domain.Student">
        <include refid="studentSql"/> where id in
        <foreach collection="list" item="stu" open="(" close=")" separator=",">
            #{stu.id}
        </foreach>

    </select>

4.4 sql代码片段

步骤
	 1.先定义 <sql id="自定义名称唯一">  sql语句, 表名,字段等 </sql>
     2.再使用, <include refid="id的值" />
<!--定义sql代码片段-->
    <sql id="studentSql">
        select id,name,email,age from student
    </sql>
<!--if
         <if test = "使用参数java对象的属性值作为判断条件  语法规则:属性名 = xxx值"
    -->
    <select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
        <include refid="studentSql"/>
        where
        <if test="name != null and name != ''">
            name = #{name}
        </if>
        <if test="age > 0">
            or age > #{age}
        </if>
    </select>

5. mybatis主配置文件

主配置文件特点:
1. 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"> 
 2.根元素,<configuration>
 3.主要包含内容:
	➢ 定义别名
	➢ 数据源
	➢ mapper 文件
<?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="jdbc.properties" />

    <!--settings:控制mybatis全局行为-->
<!--    <settings>-->
<!--        <!–设置mybatis输出日志–>-->
<!--        <setting name="logImpl" value="STDOUT_LOGGING"/>-->
<!--    </settings>-->

    <!--定义别名-->
    <typeAliases>
        <!--
            第一种方式:
            可以指定一个类型一个自定义别名
            type:自定义类型的全限定名称
            alias:别名(短小,容易记忆的)
        -->
        <!--<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
        <typeAlias type="com.bjpowernode.vo.ViewStudent" alias="vstu" />-->

        <!--
          第二种方式
          <package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)
        -->
        <package name="com.bjpowernode.domain"/>
        <package name="com.bjpowernode.vo"/>
    </typeAliases>
    <!--配置pagehelper插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor" />
    </plugins>

    <environments default="mydev">
        <environment id="mydev">
            <!--
              transactionManager:mybatis提交事务,回滚事务的方式
                 type: 事务的处理的类型
                     1)JDBC : 表示mybatis底层是调用JDBC中的Connection对象的,commit, rollback
                     2)MANAGED : 把mybatis的事务处理委托给其它的容器(一个服务器软件,一个框架(spring))
            -->
            <transactionManager type="JDBC"/>
            <!--
               dataSource:表示数据源,java体系中,规定实现了javax.sql.DataSource接口的都是数据源。
                          数据源表示Connection对象的。

               type:指定数据源的类型
                  1)POOLED: 使用连接池, mybatis会创建PooledDataSource类
                  2)UPOOLED: 不使用连接池, 在每次执行sql语句,先创建连接,执行sql,在关闭连接
                              mybatis会创建一个UnPooledDataSource,管理Connection对象的使用
                  3)JNDI:java命名和目录服务(windows注册表)
            -->
            <dataSource type="POOLED">
                <!--数据库的驱动类名-->
                <property name="driver" value="${jdbc.driver}"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="${jdbc.url}"/>
                <!--访问数据库的用户名-->
                <property name="username" value="${jdbc.user}"/>
                <!--密码-->
                <property name="password" value="${jdbc.passwd}"/>
            </dataSource>
        </environment>

    </environments>

    <!-- sql mapper(sql映射文件)的位置-->
    <mappers>
        <!--第一种方式:指定多个mapper文件-->
        <!--<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
        <mapper resource="com/bjpowernode/dao/OrderDao.xml" />-->

        <!--第二种方式: 使用包名
            name: xml文件(mapper文件)所在的包名, 这个包中所有xml文件一次都能加载给mybatis
            使用package的要求:
             1. mapper文件名称需要和接口名称一样, 区分大小写的一样
             2. mapper文件和dao接口需要在同一目录
        -->
        <package name="com.bjpowernode.dao"/>
        <!-- <package name="com.bjpowernode.dao2"/>
         <package name="com.bjpowernode.dao3"/>-->
    </mappers>
</configuration>

6. 扩展

6.1 PageHelper 分页方法

使用方法:

  1. 第一步 : 现在POM中加入PageHelper 依赖
<dependency>
 <groupId>com.github.pagehelper</groupId>
 <artifactId>pagehelper</artifactId>
 <version>5.1.10</version>
</dependency>
  1. 第二步:在mybatis主配置文件中加入插件
<!--在<environments>之前加入-->
	<plugins>
	 <plugin interceptor="com.github.pagehelper.PageInterceptor" />
	</plugins>
  1. PageHelper 对象,查询语句之前调用 PageHelper.startPage 静态方法。
@Test
public void testSelect() throws IOException {
//获取第 1 页,3 条内容
PageHelper.startPage(1,3);
 List<Student> studentList = studentDao.selectStudents();
 studentList.forEach( stu -> System.out.println(stu));
}