框架 - MyBatis框架

第1章:框架概述

1、三层架构

界面层(User Interface layer):和用户打交道的,接受用户的数据,显示请求的处理结果。(jsp ,html ,servlet)
业务逻辑层(Business Logic Layer):接收界面层传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
数据访问层(Data access layer): 与数据库打交道。主要实现对数据的增、删、改、查。
					将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。

三层对应的包
	界面层: controller包  (servlet)
	业务逻辑层: service 包(XXXService类)
	数据访问层: dao包(XXXDao类)

三层中类的交互
	用户使用界面层————> 业务逻辑层————>数据访问层(持久层)————>数据库(mysql)

三层对应的处理框架
	界面层  ———————— servlet —————— SpringMVC(框架)
	业务逻辑层 ———— service类——————Spring(框架)
	数据访问层 ———— dao类 ———————— MyBatis(框架)
	
为什么要使用三层?
	1,结构清晰、耦合度低, 各层分工明确
	2,可维护性高,可扩展性高
	3,有利于标准化
	4,开发人员可以只关注整个结构中的其中某一层的功能实现
	5,有利于各层逻辑的复用

2、框架

	框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;
另一种认为,框架是可被应用开发者定制的应用骨架、模板。
	简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。
从另一个角度来说框架一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能。
	框架安全的,可复用的,不断升级的软件。

框架的特点:
	1. 框架一般不是全能的, 不能做所有事情
	2. 框架是针对某一个领域有效。 特长在某一个方面,比如MyBatis做数据库操作强,但是他不能做其它的。
	3. 框架是一个软件

框架解决的问题:
	1)技术整合
	2)提高开发的效率

3、JDBC编程

		public List findAll() {
			Connection conn = null;
			Statement stmt = null;
			ResultSet rs = null;
			List list = new ArrayList();
			try {
				//1、注册驱动
				Class.forName("com.mysql.jdbc.Driver");
				//2、获取连接
				conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/zt","root","123");
				//3、获取数据库操作对象
				stmt = conn.createStatement();
				//4、执行sql语句
				String sql = "select * from question";
				rs = stmt.executeQuery(sql);
				//5、处理查询结果集
				while (rs.next()) {
					Integer quesitonId = rs.getInt("questionId");
					String title = rs.getString("title");
					String optionA = rs.getString("optionA");
					String optionB = rs.getString("optionB");
					String optionC = rs.getString("optionC");
					String optionD = rs.getString("optionD");
					String answer = rs.getString("answer");
					Question question = new Question(quesitonId, title, optionA, optionB, optionC, optionD, answer);
					// 创建一个ArrayList存放question对象
					list.add(question);
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				//6、释放资源
				if (rs != null){  
					try{
					    rs.close();
					}
					catch (Exception e){
					    e.printStackTrace();
					}			
				}
				if (stmt != null){  
					try{
					    stmt.close();
					}
					catch (Exception e){
					    e.printStackTrace();
					}			
				}
				if (conn != null){ 
					try{
					    conn.close();
					}
					catch (Exception e){
					    e.printStackTrace();
					}			
				}
			}
			return list; //返回集合 存储所有的查询结果
		}
  • 3.2 使用 JDBC 的缺陷
    1) 代码比较多,开发效率低
    2) 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
    3) 对 ResultSet 查询的结果,需要自己封装为 List
    4) 重复的代码比较多些
    5) 业务代码和数据库的操作混在一起

4、MyBatis框架概述

  • 4.1 MyBatis 框架

    MyBatis 本是 apache 的一个开源项目 iBatis。目前代码在 Github上。
    2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。
    2013 年 11 月迁移到 Github。
    iBatis 一词来源于“internet”和“abatis”的组合,是一个基于 Java 的持久层框架。
    iBatis 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAOs)
    当前,最新版本是MyBatis 3.5.5 ,其发布时间是2020年6月4日。
    
    	MyBatis 是一个优秀的基于 java 的持久层框架,内部封装了 jdbc,开发者只需要关注 sql 语句本身,
    而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程。
    	MyBatis 通过【xml】 或 【注解】 两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的动态参数
    进行映射生成最终执行的 sql 语句,最后由 MyBatis 框架执行 sql 并将结果映射为 java对象并返回。
    
    MyBatis SQL Mapper Framework for Java (sql映射框架)
    	1)sql mapper :sql映射
    		可以把数据库表中的一行数据  映射为 一个java对象。
    		一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据
    	2) Data Access Objects(DAOs) : 数据访问对象, 对数据库执行增删改查。
    
  • 4.2 MyBatis提供了哪些功能

    1) 注册数据库的驱动,例如 Class.forName(“com.mysql.jdbc.Driver”))
    2) 创建了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()
    

    开发人员做的是: 提供sql语句
    开发人员提供sql语句————> MyBatis处理sql————> 开发人员得到List集合或java对象(表中的数据)

5、总结

MyBatis是一个sql映射框架,提供的数据库的操作能力。增强的JDBC。
使用MyBatis让开发人员集中精神写sql就可以了,不必关心Connection,Statement,ResultSet的创建,销毁,sql的执行。

第2章:MyBatis 框架快速入门

1、入门案例

  • MyBatis 开发准备,搭建 MyBatis 开发环境,实现第一个案例:查询数据库中表的所有信息

  • 0)在GitHub 上面下载mybatis

    我下载了【mybatis-3.5.1.zip】,下载之后,里面有mybatis-3.5.1.pdf文档,可以教我们怎样使用mybatis;
    如果英文看不懂的话,可以直接百度搜索中文手册,我找到了【MyBatis 3.5.2 中文参考文档.pdf】

  • 1)创建mysq|数据库和表student

    数据库名 zt ;
    表名 	student 
    -----------------------------------------------------------------------------------
    id(int 11, 主键)		name(varchar 255)	email(varchar 255)	age(int 11)
    -----------------------------------------------------------------------------------
    1001				张三					zhangsan@qq.com		20
    1002				李四					lisi@qq.com			25
    -----------------------------------------------------------------------------------
    
    CREATE TABLE `student` (
    	`id` int(11) NOT NULL ,
    	`name` varchar(255) DEFAULT NULL,
    	`email` varchar(255) DEFAULT NULL,
    	`age` int(11) DEFAULT NULL,
    	PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  • 2) 创建maven版java项目

    打开IDEA,新建一个空的工程【11-mybatis】
    新建一个maven版普通java项目,选择模板:maven-archetype-quickstart
    坐标:
    	com.yuming
    	ch01-mybatis-first
    	1.0-SNAPSHOT
    最后就建好了这个项目(Module)【ch01-mybatis-first】
    
  • 3)整理项目:

    1、删除src下默认创建的App类文件;
    2、创建缺少的resources目录并标识。右键resources ———— Mark Directory as —————— Resources Root
    3、pom文件中:删掉无用的一些标签:name和url标签、build标签;
    4、pom文件中:将jdk版本1.7要修改为1.8;
    
  • 4)pom.xml 中加入mybatis依赖、mysq1驱动的依赖

<!--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>5.1.9</version>
    </dependency>
  • 5)pom.xml中设置扫描资源文件
  <build>
     <resources>
     	<resource>
     	    <directory>src/main/java</directory>	<!--目录-->
     	    <includes>			      <!--包括目录下面的所有 .properties,  .xml 文件都会扫描到-->
     	    	<include>**/*.properties</include>
     	    	<include>**/*.xml</include>
     	    </includes>							
     	    <filtering>false</filtering>   <!--filtering 为 false 表示不启用过滤器 -->
     	</resource>
     </resources>
  </build>
  • 6) 编写Student实体类————保存表中的一行数据的
package com.yuming.entity;

//类名推荐和表名一样。容易记忆
public class Student {
    //定义属性, 推荐是属性名和列名一样。
    private Integer id;
    private String name;
    private String email;
    private Integer age;
    
    //set、get、toString、有参和无参构造方法
}    
  • 7)编写Dao接口 StudentDao————定义操作数据库的方法
package com.yuming.dao;
import com.yuming.entity.Student;
import java.util.List;

//接口操作student表
public interface StudentDao {
    //接口中抽象方法的public abstract可以省略。

    //查询student表的所有的数据
    List<Student> selectStudents();

    int insertStudent(Student student);

    int deleteStudent(int id);

    int updateStudent(Student student);
}
  • 8)编写StudentDao接口的 sql映射文件: StudentDao.xml
        sq1映射文件: 写sq1语句的。 一般一个表一个sq1映射文件(.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.yuming.dao.StudentDao">
    <select id="selectStudents" resultType="com.yuming.entity.Student">
		select id,name,email,age from student order by id
	</select>

	<insert id="insertStudent">
		insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age})
	</insert>

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

	<update id="updateStudent">
		update student set age = #{age} where id=#{id}
	</update>

</mapper>

<!--
sql映射文件(sql mapper): 写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的。
		约束文件作用: 限制、检查在当前文件中出现的标签,属性必须符合mybatis的要求。

	3.<mapper>是当前文件的根标签,必须有的。
		namespace:命名空间,唯一值的, 可以是自定义的字符串。
		建议使用dao接口的全限定名称,以保证唯一性。com.yuming.dao.StudentDao

	4.在当前文件中,可以使用特定的标签,表示数据库的特定操作。
		<select>:表示执行查询,select语句
		<insert>:表示插入, 放的是insert语句
		<update>:表示更新, 放的是update语句
		<delete>:表示删除, 执行的delete语句

	5.参数说明
		select: 表示查询操作。
		id: 你要执行的sql语法的唯一标识, mybatis会使用这个id的值来找到要执行的sql语句
		    可以自定义,但是建议使用接口中的方法名称。

		resultType:表示结果类型的, 是sql语句执行后得到的查询结果集ResultSet,遍历这个ResultSet得到java对象的类型。
			   值写的类型的全限定名称

 -->
  • 9) 创建MyBatis主配置文件
    一个项目就一个主配置文件。
    主配置文件提供了:数据库的连接信息、sq1映射文件的位置信息…

    项目 src/main/resources 目录下面创建主配置文件:名称为 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>

    <!--环境配置: 数据库的连接信息
        default必须和下面某一个environment的id值一样。告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库 -->
    <environments default="myFirst">
        <!-- environment : 一个数据库信息的配置环境。id:一个唯一值,自定义,表示环境的名称。-->
        <environment id="myFirst">
            <!-- 配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚) -->
            <transactionManager type="JDBC"/>
            <!--数据源的类型: POOLED 表示使用数据库的连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/zt"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>

        <environment id="mySecond">  <!--可以配置多个数据库环境-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/onlinedb"/>
                <property name="username" value="root"/>
                <property name="password" value="123123"/>
            </dataSource>
        </environment>

    </environments>

    <!-- 指定sql mapper(sql映射文件)的位置-->
    <mappers>
        <!--可以有多个mapper标签,一个mapper标签指定一个sql映射文件的位置。从类路径(target/clasess)开始的路径信息。-->
        <mapper resource="com/yuming/dao/StudentDao.xml"/>

        <!--<mapper resource="com/yuming/dao/TeacherDao.xml"/>-->
    </mappers>

</configuration>
  • 10)创建测试类TestMyBatis
    src/test/java/com/yuming/ 创建 TestMyBatis.java 文件
    下面是测试类中的第一个测试方法: 获取SqlSession对象。SqlSession 能执行 sql 语句
@Test
public void testSelect() throws IOException {
	//访问mybatis读取student数据

	//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
	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对象. SqlSession 能执行 sql 语句
	SqlSession sqlSession = factory.openSession();

	//6.【重要】指定要执行的sql语句的标识。  sql映射文件中的namespace + "." + 标签的id值
	String sqlId = "com.yuming.dao.StudentDao.selectStudents";
	//7.【重要】通过sqlId找到语句,执行sql语句。
	List<Student> studentList = sqlSession.selectList(sqlId);

	//8. 循环输出查询结果
	//studentList.forEach( student -> System.out.println(student));//Lambda 表达式
	for (Student stu : studentList) {
		System.out.println("查询的学生:" + stu);  //默认调用stu对象的toString方法
	}
	/*
	 查询的学生:student{id=1001, name='张三', email='zhangsan@qq.com', age=20}
	 查询的学生:student{id=1002, name='李四', email='lisi@qq.com', age=25}
	 */

	//9.关闭SqlSession对象
	sqlSession.close();
}

  其中 List< Student> studentList = sqlSession.selectList(sqlId);
  近似等价的jdbc代码:

Connection conn = 获取连接对象
String sql=”select id,name,email,age from student order by id”;
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
  • 11)配置日志功能
    mybatis.xml 主配置文件加入日志配置,可以在控制台输出执行的 sql 语句和参数:
<settings>
	<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
  • 【总结】:
    pom.xml — Student.java — StudentDao.java — StudentDao.xml(sql映射文件) —mybatis.xml(主配置文件)—MyBatisTest测试类:使用mybatis执行sql语句

2、基本的CRUD

上面讲了select操作,现在来看看insert ,update ,delete等操作

注意:mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手动提交事务 sqlSession.commit();

  • 添加 insert插入操作:

    (1)StudentDao 接口中增加方法
    	int insertStudent(Student student);
    
    (2)StudentDao.xml映射文件中 加入 sql 语句
    	<insert id="insertStudent">
    		insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age})
    	</insert>
    	
    	注:这里的#{属性名}也是一个占位符,相当于传统jdbc中的问号?占位符
    		insert into student(id,name,email,age) values(?,?,?,?) 
    
    (3)测试类中增加测试方法
    	------------------------------------------------------------------------------------
    	    @Test
    	    public void testInsert() throws IOException {
    
    		String config = "mybatis.xml";
    		InputStream in = Resources.getResourceAsStream(config);
    
    		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    		SqlSessionFactory factory = builder.build(in);
    		SqlSession sqlSession = factory.openSession();
    
    		//指定要执行的sql语句的标识 为 id = insertStudent
    		String sqlId = "com.yuming.dao.StudentDao.insertStudent";
    		//使用插入的方法
    		Student student = new Student(1004, "tom", "123@163.com", 50);
    		int count = sqlSession.insert(sqlId, student);
    
    		//运行之后,去数据库看student表,发现并没有增加这条数据???
    		//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
    		sqlSession.commit();
    
    		System.out.println("执行insert的结果=" + count); //执行insert的结果=1
    
    		sqlSession.close();
    	    }		
    	------------------------------------------------------------------------------------
    
  • delete删除操作:

    (1)StudentDao  接口中增加方法
    	int deleteStudent(int id);
    
    (2)StudentDao.xml  增加 sql  语句
    	<delete id="deleteStudent">
    		delete from student where id=#{studentId}
    	</delete>
    
    (3)增加测试方法
    	------------------------------------------------------------------------------------
    	    @Test
    	    public void testDelete() throws IOException {
    
    		String config = "mybatis.xml";
    		InputStream in = Resources.getResourceAsStream(config);
    
    		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    		SqlSessionFactory factory = builder.build(in);
    		SqlSession sqlSession = factory.openSession();
    
    		//指定要执行的sql语句的标识 为 id = deleteStudent
    		String sqlId = "com.yuming.dao.StudentDao.deleteStudent";
    		//执行删除
    		int id = 1005;
    		int count = sqlSession.delete(sqlId,id);
    
    		//提交事务
    		sqlSession.commit();
    
    		System.out.println("执行delete的结果=" + count); //执行delete的结果=1
    
    		sqlSession.close();
    	    }
    	------------------------------------------------------------------------------------
    
  • update更新操作:

    (1)StudentDao  接口中增加方法
    	int updateStudent(Student student);
    
    (2)StudentDao.xml  增加 sql  语句
    	<update id="updateStudent">
    		update student set age = #{age} where id=#{id}
    	</update>
    
    (3)增加测试方法
    	------------------------------------------------------------------------------------
    	    @Test
    	    public void testUpdate() throws IOException {
    
    		String config = "mybatis.xml";
    		InputStream in = Resources.getResourceAsStream(config);
    
    		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    		SqlSessionFactory factory = builder.build(in);
    		SqlSession sqlSession = factory.openSession();
    
    		//指定要执行的sql语句的标识 为 id = updateStudent
    		String sqlId = "com.yuming.dao.StudentDao.updateStudent";
    		//执行更新
    		Student student = new Student();
    		student.setId(1003);// 要修改的 id
    		student.setAge(33); // 要修改的年龄值
    		int count = sqlSession.delete(sqlId,student);
    
    		//提交事务
    		sqlSession.commit();
    
    		System.out.println("执行update的结果=" + count); //执行update的结果=1
    
    		sqlSession.close();
    	    }
    	------------------------------------------------------------------------------------
    

3、【关于target/classes下找不到资源配置文件】

(1)当我们创建了src/main下面的resources文件夹,并且已经标识为资源文件夹,然后创建了a.xml文件;
(2)然后在src/main/java下面创建了 b.xml 文件、c.properties文件,
    并且在pom文件指定了扫描src/main/java目录下面的所有 .properties,  .xml 文件;

之后运行后,可能在target/classes下面并没有找到上面的a.xml文件,这是IDEA出现了小bug,不是我们程序的问题

解决办法:
	方法一:在IDEA右侧边缘打开Maven窗口,先双击clean清理掉target目录,然后在双击compile编译,再执行程序

	方法二:点击IDEA上方工具栏:Build ———— Rebulid Project,再执行程序

	方法三:File - Invalidate caches/Restart —— Invalidate and Restart。可以将IDEA中之前的缓存清理掉并且重启IDEA
	
	方法四:手工移动,直接将src下面的这几个文件复制到target/classes下面

4、主要对象的介绍

1、Resources 类:顾名思义就是资源,负责读取主配置资源文件,是MyBatis中的一个类,
	InputStream in = Resources.getResourceAsStream("MyBatis.xml");

2、SqlSessionFactoryBuilder 类 : 创建SqlSessionFactory对象, 
	SqlSessionFactoryBuilder builder  = new SqlSessionFactoryBuilder();
	SqlSessionFactory factory = builder.build(in);

3、SqlSessionFactory 接口 : 重量级对象, 程序创建该对象耗时比较长,使用资源比较多,
	是线程安全的,所以一个应用只需要一个该对象即可。

	SqlSessionFactory接口的作用: 获取SqlSession对象。

	openSession()方法说明:
		➢  openSession(true):创建一个有自动提交功能的 SqlSession
		➢  openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
		➢  openSession():同 openSession(false)
		
		SqlSession sqlSession1 = factory.openSession();  //非自动提交事务的SqlSession对象
 		SqlSession sqlSession2 = factory.openSession(false); //非自动提交...
		SqlSession sqlSession3 = factory.openSession(true); //自动提交...

4、SqlSession 接口: 
	SqlSession 接口对象 用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,
		一次会话以SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。
		其中定义了操作数据的方法 例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()等等

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

5、创建工具类

  • 1、创建 MyBatisUtil 工具类
    com.yuming.util.MyBatisUtil.java
public class MyBatisUtil {

    //将factory对象定义为全局变量,以便在下面多个方法可以使用
    private static SqlSessionFactory factory = null;

    //首先要获取SqlSessionFactory对象 ,只需要一个该对象即可。那么可以放在静态代码块状,在类加载时执行,并且只执行一次。
    static {
		String config = "mybatis.xml";
		try {
	    	InputStream in = Resources.getResourceAsStream(config);// 读取配置文件
	    	factory = new SqlSessionFactoryBuilder().build(in);// 创建 SqlSessionFactory 对象
		} catch (IOException e) {
	    	e.printStackTrace();
		}
    }

    //【获取SqlSession对象】
    public static SqlSession getSqlSession() {
		SqlSession sqlSession = null;
		if (factory != null) {
	    	sqlSession = factory.openSession();//没有参数,非自动提交事务
		}
		return sqlSession;
    }
}
  • 2、使用MyBatisUtil工具类
    在com.yuming.TestMyBatis测试类中加一个测试方法:
@Test
public void testSelect2(){
	SqlSession sqlSession = MyBatisUtil.getSqlSession();//直接调用工具类的方法,获取SqlSession对象

	String sqlId = "com.yuming.dao.StudentDao.selectStudents";
	List<Student> studentList = sqlSession.selectList(sqlId); //执行sql语句
	studentList.forEach( student -> System.out.println(student));//结果输出
	sqlSession.close(); //关闭sqlSession
}

6、MyBatis 使用传统 Dao 开发方式

  • 不难发现,在上面程序中,其实并没有用到StudentDao接口
    主要是在MyBatisTest测试类中直接写对应的测试方法,进行数据库的增删改查。
        pom.xml —— Student.java —— StudentDao.java接口(没有使用到)—— StudentDao.xml(sql映射文件)
        ——mybatis.xml(主配置文件)———MyBatisTest测试类:使用mybatis执行sql语句

  • 现在演示使用 Dao接口的实现类, 操作数据库进行增删改查:

    1、创建第二个java项目【ch02-mybatis-dao】
    	创建maven版java项目(Module)、
    	整理项目、
    	pom.xml 中加入mybatis依赖、mysq1驱动的依赖、
    	pom.xml中设置扫描资源文件
    
    2、创建相关的类和接口:	
    	创建Student实体类————保存表中的一行数据的
    	创建Dao接口 StudentDao ————定义操作数据库的方法
    	创建StudentDao接口的 sq1映射文件: StudentDao.xml ——————> 使用自己建的模板【mybatis-sqlmapper】
    	创建MyBatis主配置文件				——————> 使用自己建的模板【mybatis-config】
    	创建MyBatisUtil工具类
    	
    	注:这些类和接口可以直接复制第一个项目里面的
    
    【IDEA的模板设置】:
    
    	file —— settings ———— Editor ———— File and Code Templates(文件和代码模板)
    	在右边的窗口中,可以对不同的文件类型进行一个模板的设置
    
    	我们在这里可以设置【sql映射文件】的模板,不用像之前要一步步写了
    		File 下面点击+号,创建模板:
    		上面写模板名和扩展名:name= mybatis-sqlmapper ; Extension= xml
    		下面写模板的具体内容:
    		---------------------------------------------------------------
    		<?xml version="1.0" encoding="UTF-8" ?>
    		<!DOCTYPE mapper
    			PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    			"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    		<mapper namespace="命名空间建议使用dao接口的全限定名称以保证唯一性">
    
    			<select id="" resultType="">
    
    			</select>
    
    		</mapper>
    		---------------------------------------------------------------
    		然后点击Apply和OK
    		然后就可以使用了:
    		右键dao目录,new —— mybatis-sqlmapper,然后给文件命名就可以开始基于模板进行编写了。
    
    3、创建StudentDao接口的实现类:com.yuming.dao.StudentDaoImpl类
    	-------------------------------------------------------------------------------
    	public class StudentDaoImpl implements StudentDao
    	-------------------------------------------------------------------------------
    	实现接口里面的方法:
    	-------------------------------------------------------------------------------
    	    @Override
    	    public List<Student> selectStudents() {
    			//直接调用自己工具类的方法,获取SqlSession对象
    			SqlSession sqlSession = MyBatisUtil.getSqlSession();
    
    			String sqlId = "com.yuming.dao.StudentDao.selectStudents";
    			List<Student> studentList = sqlSession.selectList(sqlId); //执行sql语句
    			sqlSession.close(); //关闭sqlSession
    			return studentList;
    	    }
    	-------------------------------------------------------------------------------
    
    4、创建测试类MyBatisTest,添加测试方法testSelect()
    	
    	@Test
    	public void testSelect(){
    		StudentDao dao = new StudentDaoImpl();
    		List<Student> studentList = dao.selectStudents();
    		studentList.forEach(student -> System.out.println(student));
    	}
    
    5、以此类推,可以分别创建对应的 insert、delete、update操作
    
  • 传统 Dao 开发方式的分析:

    	在前面例子中【自定义Dao接口实现类】时发现一个问题:	
    
    	Dao 的实现类其实并没有干什么实质性的工作,
    	它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,
    	真正对 数据库 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。
    	
    	所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,
    	对数据库进行操作。  这种对 Dao 的实现方式称为 【Mapper的动态代理方式】。
    	
    	Mapper 动态代理方式 无需程序员实现 Dao 接口。
    	接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。
    

第3章:MyBatis框架 Dao代理

1、动态代理

动态代理:使用sqlSession.getMapper(dao接口.class) 获取dao接口的实现类对象,不需要自己创建dao接口实现类。

(1)将第二个java项目【ch02-mybatis-dao】复制一份
	重命名为【ch03-mybatis-daoproxy】,删掉里面的.iml文件和target目录,
	打开pom文件,将artifactId标签改成这个新项目的名字
	
	在IDEA中导入这个项目:
	File - new - Module from Existing Sources... 找到这个项目的位置,ok
	点击【import module from external module】,选择它下面的【Maven】
	- 然后一直Next - Finish

	File - Project Structure窗口,点击左边的Modules,选中该项目,
	在右边的【Dependencies】看是否有指定的jdk,如果没有就选择一个。

	src/main/resources这个文件夹要重新标识一下:
	右键resources ———— Mark Directory as —————— Resources Root

(2)去掉 Dao接口实现类:com.yuming.dao.StudentDaoImpl
	
(3)在 TestMyBatis中,调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。
	--------------------------------------------------------------------------------------
	    @Test
	    public void testSelect(){
		// StudentDao dao = new StudentDaoImpl(); 不需要我们自己建dao接口的实现类

		/**
		 * 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口.class)
		 * getMapper能创建并获取dao接口的实现类对象。
		 */
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao = sqlSession.getMapper(StudentDao.class); //动态获取接口的实现类对象
    	
    	//可以看看这个接口实现类是什么
   		// System.out.println(dao.getClass().getName());//com.sun.proxy.$Proxy2   确实是jdk的动态代理
		
		List<Student> studentList = dao.selectStudents();
		studentList.forEach(student -> System.out.println(student));
		sqlSession.close();
	    }
	--------------------------------------------------------------------------------------
  • 原理:
    在这里插入图片描述

2、传入参数

  • 传入参数: 从java代码中把数据传入到mapper文件的sql语句中

    【ch03-mybatis-daoproxy】复制一份为【ch04-mybatis-param】,其他具体过程同上
    然后将StudentDao接口中的方法都删掉,StudentDao.xml映射文件里面的写的SQL语句标签也删掉,重新改造:

    分类:
    1、parameterType属性
    2、一个简单类型的参数
    3、多个参数,使用 @Param 命名的参数
    4、多个参数,使用java对象
    5、多个参数,按位置传值 (了解)
    6、多个参数,使用 Map 集合 (了解)
    7、# 和 $

2.1、parameterType属性

写在mapper文件中的 一个属性。 表示dao接口中方法的参数的数据类型。

		------------------------------------------------------------------------------------------------------------
		例如StudentDao接口:
			//抽象方法——根据参数id查询数据库中对应的学生信息
			Student selectById(Integer id);

		mapper文件(StudentDao.xml):
			<select id="selectById" parameterType="java.lang.Integer" resultType="com.yuming.entity.Student">
				select id ,name, email ,age from student where id = #{id}
			</select>
		------------------------------------------------------------------------------------------------------------

		parameterType它的值是java数据类型的【全限定名称】或者是mybatis定义的【类型别名】
			例如:parameterType="java.lang.Integer" 或者 parameterType="int"

		<select>,<insert>,<update>,<delete>都可以使用 parameterType 指定类型。

		注意:  parameterType不是强制的,mybatis通过反射机制能够发现接口参数的数据类型。
			所以可以没有。 一般我们也不写。

2.2、一个简单类型的参数

简单类型: MyBatis把 【java的基本数据类型】和【String】 都叫简单类型。

在mapper文件获取简单类型的一个参数的值,使用 #{任意字符}

接口方法:
	Student selectStudentById(Integer id);

mapper 文件:
	<select id="selectStudentById" resultType="com.yuming.entity.Student">
		select id ,name, email ,age from student where id = #{gtdhghy}
	</select>
	
	这里的#{gtdhghy} , gtdhghy 是自定义的变量名称,和方法参数名id无关。

测试方法:
    @Test
    public void testSelectStudentById(){
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao = sqlSession.getMapper(StudentDao.class); //动态获取接口的实现类对象

		Student student = dao.selectStudentById(1002);//根据id查询一个学生
		System.out.println(student);
		sqlSession.close();
    }

【mybatis是封装的jdbc操作】

mapper 文件:
	<select id="selectStudentById" resultType="com.yuming.entity.Student">
		select id,name,email,age from student where id = #{gtdhghy}
	</select>	

使用 #{} 之后, mybatis执行sql是使用的jdbc中的PreparedStatement对象
由mybatis执行下面的代码:
 1. mybatis创建Connection , PreparedStatement对象
	    String sql="select id,name, email,age from student where id=?";
	    PreparedStatement ps = conn.preparedStatement(sql);
	    ps.setInt(1,1001);

 2. 执行sql封装为resultType="com.yuming.entity.Student"这个对象
	    ResultSet rs = ps.executeQuery();
	    Student student = null;
	    while(rs.next()){
	       //从数据库取表的一行数据, 存到一个java对象属性中
	       student = new Student();
	       student.setId(rs.getInt("id));
	       student.setName(rs.getString("name"));
	       student.setEmail(rs.getString("email"));
	       student.setAge(rs.getInt("age"));
	    }
	   return student;  //给了dao方法调用的返回值

2.3、多个参数,使用 @Param 命名的参数

当 Dao 接口方法多个参数,需要通过名称使用参数:
   1)在方法形参前面加入 @Param(“自定义参数名”)
   2)然后在 mapper 文件使用 #{自定义参数名}

接口方法:
	List<Student> selectMultiParam(@Param("myname") String name,@Param("myage") Integer age);

mapper文件:
	<select id="selectMultiParam" resultType="com.yuming.entity.Student">
		select * from student where name=#{myname} or age=#{myage}
	</select>

测试方法:
    @Test
    public void testSelectMultiParam(){
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao = sqlSession.getMapper(StudentDao.class);

		//查询name=李四 or age= 20 的所有学生信息
		List<Student> studentList = dao.selectMultiParam("李四", 20); //传多个参数

		studentList.forEach(student -> System.out.println(student));
		sqlSession.close();
    }

2.4、多个参数,使用java对象

使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。

语法格式: #{属性名, javaType=数据类型, jdbcType=数据类型}
常用简化格式: #{属性名}

注:javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。

在这里插入图片描述

创建保存参数值的对象:QueryParam
	package com.yuming.vo;
	public class QueryParam {
		private String paramName;
		private Integer paramAge;
		//set、get方法
	}

接口方法:	
	 List<Student> selectMultiObject(QueryParam param);

mapper 文件:
	<select id="selectMultiObject" resultType="com.yuming.entity.Student">
		select * from student  where name = #{paramName} or age = #{paramAge}
	</select><select id="selectMultiObject" resultType="com.yuming.entity.Student">
		select * from student
		where name = #{paramName, javaType=java.lang.String, jdbcType=VARCHAR}
		or age = #{paramAge, javaType=java.lang.Integer, jdbcType=INTEGER}
	</select>

测试方法:
    @Test
    public void testSelectMultiObject(){
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao = sqlSession.getMapper(StudentDao.class);

		//查询name=李四 or age= 20 的所有学生信息
		QueryParam param = new QueryParam();
		param.setParamName("李四");
		param.setParamAge(20);

		List<Student> studentList = dao.selectMultiObject(param);  //传java对象作为参数

		studentList.forEach(student -> System.out.println(student));
		sqlSession.close();
    }

注:也可以直接使用Student实体类的对象进行传值,不新建这个 QueryParam 类。

2.5、多个参数,按位置传值 (了解)

参数位置从 0 开始, 引用参数语法: #{ arg位置 } ,第一个参数是#{arg0}, 第二个是#{arg1}

注意:
    mybatis.3.4之前,使用 #{0}, #{1}…
    mybatis.3.4之后,使用 #{arg0}, #{arg1}…

接口方法:
	List<Student> selectMultiPosition( String name, Integer age);

mapper 文件:
	<select id="selectMultiPosition" resultType="com.yuming.entity.Student">
		select * from student where name = #{arg0} or age=#{arg1}
	</select>

测试方法:
	@Test
	public void testSelectMultiPosition(){
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao = sqlSession.getMapper(StudentDao.class);

		List<Student> studentList = dao.selectMultiPosition("李四",20);
		studentList.forEach(student -> System.out.println(student));
		sqlSession.close();
	}

2.6、多个参数,使用 Map 集合 (了解)

Map集合可以存储多个值,使用Map向mapper文件一次传入多个参数。
Map集合使用String的key、Object类型的value存储参数。
mapper 文件使用 #{key} 引用参数值

接口方法:
	List<Student> selectMultiByMap(Map<String,Object> map);

mapper 文件:
	<!--多个参数,使用Map , 使用语法 #{map的key}-->
	<select id="selectMultiByMap" resultType="com.yuming.entity.Student">
		select * from student where name = #{keyName} or age=#{keyAge}
	</select>

测试方法:
	@Test
	public void testSelectMultiByMap(){
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao = sqlSession.getMapper(StudentDao.class);

		Map<String,Object> map = new HashMap<>();
		map.put("keyName","李四");
		map.put("keyAge","20");

		List<Student> studentList = dao.selectMultiByMap(map);
		studentList.forEach(student -> System.out.println(student));
		sqlSession.close();
	}

2.7、# 和 $

  • (1)#:占位符
    告诉 mybatis 使用实际的参数值代替。
    并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“ ? ”
    这样做更迅速,更安全,可避免sql注入,通常也是首选做法

  • (2) $ :字符串替换
    告诉 mybatis 使用 $ 包含的“字符串”替换所在位置。
    使用 Statement 把 sql 语句和 $ { }的内容 拼接 起来。
    主要用在替换表名,列名,不同列排序等操作。如果能确定数据是安全的。可以使用 $

接口方法:
	//  使用 #{}
	List<Student> selectByName (@Param("myname") String name);

	//  使用 ${}
	List<Student> selectByName2(@Param("myname2") String name);

mapper 文件:
	<select id="selectByName" resultType="com.yuming.entity.Student">
		select * from student where name=#{myname}                 <!--使用 #{}-->
	</select>
	
	<select id="selectByName2" resultType="com.yuming.entity.Student">
		select * from student where name=${myname2}              <!--使用 ${}-->
	</select>

测试方法:
	@Test
	public void testSelectByName(){
		......
		List<Student> studentList = dao.selectByName("张三");
		......
	}
	
	@Test
	public void testSelectByName2(){
		......
		List<Student> studentList = dao.selectByName2("'张三'"); //得加一对单引号,保证sql语句的正确性

		//List<Student> studentList = dao.selectByName2("'张三' or 1=1");  //存在sql注入的危险
		......
	}

结果:
	......
	==>  Preparing: select * from student where name=?        
	==> Parameters: 张三(String)
	......


	......
	==>  Preparing: select * from student where name='张三' 
	==> Parameters: 
	......

(3)# 和 $ 区别
   1)# 使用 ?在sql语句中做占位的, 使用PreparedStatement执行sql,效率高
   2)# 能够避免sql注入,更安全。
   3)$ 不使用占位符,是字符串 拼接方式,使用Statement对象执行sql,效率低
   4)$ 有sql注入的风险,缺乏安全性。
   5)$ 可以替换 表名 或者 列名

接口方法:
    //  使用 ${},完成字符串拼接,按照列名进行排序,列名由传来的参数确定
    List<Student> selectUse$Order(@Param("colName") String colName);

mapper 文件:
    <!--使用 ${} ,替换列名-->
    <select id="selectUse$Order" resultType="com.yuming.entity.Student">
		select * from student order by ${colName}
    </select>

测试方法:
    @Test
    public void testSelectUse$Order(){
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao = sqlSession.getMapper(StudentDao.class);

		//使用 ${},完成字符串拼接,按照列名进行排序,列名由传的参数确定
		List<Student> studentList = dao.selectUse$Order("age"); //按照age 年龄排序

		studentList.forEach(student -> System.out.println(student));
		sqlSession.close();
    }
  • 【拓展:常用包名的命名】

    vo:	value object , 放一些存储数据的类。
    	比如说, 提交请求参数 name ,age 。现在想把name ,age 传给一个service 类。
    
    vo:	view object , 从servlet把数据返回给浏览器使用的类,表示显示结果的类。
    
    pojo:	普通的有set、get方法的java类。 普通的java对象
    
    	Servlet --- StudentService( addStudent( MyParam  param)  )
    
    entity(domain域): 实体类, 和数据库中的表对应的类 
    

3、封装 MyBatis 的输出结果

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

3.1、resultType 结果类型

	resultType: 执行 sql 得到 ResultSet结果集 转换后的类型,使用类型的完全限定名或别名。 
	注意:	如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。
		resultType 和 resultMap,不能同时使用。

	1、resultType的值: 
		(1)类型的全限定名称   
		(2)类型的别名, 例如 java.lang.Integer别名是int
	
		可以定义 自定义类型的别名:
			1)在MyBatis主配置文件中定义,使<typeAlias>定义别名
				<typeAliases>
					<typeAlias type="com.yuming.entity.Student" alias="stu" />
				</typeAliases>

			2)然后可以在resultType中使用自定义别名
				<select id="selectAll" resultType="stu">

		第二种方式
			1) 在MyBatis主配置文件中定义,  使用<package>
				name值是包名, 然后这个包中的所有类,类名就是别名(类名不区分大小写)
				
				<typeAliases>
					<package name="com.yuming.entity"/>
				</typeAliases>
			
			2)然后可以在resultType中直接使用类名,不用使用全限定名称,或者自定义其他的别名
				<select id="selectAll" resultType="Student">

	2、处理方式:
		1)MyBatis执行sql语句, 然后MyBatis调用类的无参数构造方法,创建对象。
		2)MyBatis把 ResultSet结果集 中的 指定的列值 赋值给对象的同名属性。

		举例:
			<select id="selectAll" resultType="com.yuming.entity.Student">
				select id ,name, email ,age from student
			</select>

		对等的jdbc:
			ResultSet rs = stmt. 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"))
				studentList.add(student);
			}

	3、除了上面演示过的返回java对象类型,还有返回简单类型:
		--------------------------------------------------------------------------
		接口方法:
			int countStudent();

		mapper 文件:
			<select id="countStudent" resultType="java.lang.Integer">
			或者
			<select id="countStudent" resultType="int"> 
				select count(*) from student
			</select>

		测试方法:
			@Test
			public void testRetunInt(){
				SqlSession sqlSession = MyBatisUtil.getSqlSession();
				StudentDao dao = sqlSession.getMapper(StudentDao.class);

				int i = dao.countStudent();
				System.out.println("学生的数量:" + i); //学生的数量:7
				sqlSession.close();
			}		
		--------------------------------------------------------------------------
		
	4、还有返回Map集合:
		返回Map: {列名1=列值1,列名2=列值2,列名3=列值3 ......}
		
			1)列名是map的key, 列值是map的value
			2) 只能最多返回一行记录。多余一行是错误

		--------------------------------------------------------------------------			
		接口方法:
		    Map<Object,Object> selectMapById(Integer id);

		mapper 文件:
		    <select id="selectMapById" resultType="java.util.HashMap">
				select id,name,email from student where id=#{stuid}
		    </select>

		测试方法:
		    @Test
		    public void testSelectMapById(){
				SqlSession sqlSession = MyBatisUtil.getSqlSession();
				StudentDao dao = sqlSession.getMapper(StudentDao.class);

				Map<Object,Object> map = dao.selectMapById(1001);
				System.out.println("map:  "+map);  
				sqlSession.close();
		    }

		结果:
			map:  {name=张三, id=1001, email=zhangsan@qq.com}
		--------------------------------------------------------------------------

3.2、resultMap 结果映射

	可以自定义 sql 的结果和 java 对象属性的映射关系
		1)你自定义 哪个列值赋值给 哪个属性
		2)当你的列名和属性名不一样时,一定使用resultMap

	使用方式:
		1)先定义 resultMap, 指定列名和属性的对应关系。
		2)在<select>中把 resultType 替换为 resultMap。(resultType 和 resultMap,不能同时使用)
		
		mapper文件:

		    这里id: 自定义的这个resultMap的名称 ---- type:java类型的全限定名称
		    <resultMap id="studentMap" type="com.yuming.entity.Student">
				<id	    column="id"	    property="id" />	 <!--主键列,使用id标签-->
				<result column="name"	property="email" />	 <!--非主键列,使用result-->
				<result column="email"	property="name" />
				<result column="age"	property="age" />
		    </resultMap>

		    <select id="selectAllStudents" resultMap="studentMap">
				select id, name, email , age from student
		    </select>
		
		结果:
			student{id=1001, name='zhangsan@qq.com', email='张三', age=33}
			student{id=1002, name='lisi@qq.com', email='李四', age=25}
			student{id=1026, name='123@163.com', email='tom22', age=50}

3.3、实体类属性名 和 列名不同的处理方式

	创建类com.yuming.entity.Student2,该类的属性名和数据库中student表的列名都不同,
	如何将查询到数据库中student表的各个列的值返回给student2对象各个属性呢?

	(1)第一种方式:使用<resultMap>
		即上面说的使用 resultMap 结果映射。
		先定义 resultMap, 指定列名和属性的对应关系,然后在<select>标签里面指定resultMap属性

	(2)第二种方式:使用列别名 和 <resultType>
		
		之前说过,resultType的默认原则是 同名的列值赋值给同名的属性, 
		所以说,我们可以使用列别名(java对象的属性名),达到列别名 和 对应的属性名 同名

		<select id="selectDiffColProperty" resultType="com.yuming.entity.Student2">
			select id as id2 ,name as name2, email as email2 , age as age2 from student
		</select>

4、模糊查询 like

模糊查询的实现有两种方式:

方法一:在java代码中 指定 like的内容: String name = “%李%”;
   然后mapper 文件的 sql 语句直接使用: …like #{name}

方法二:java代码只用提供关键字:String name = “李”;
   然后在mapper 文件的 sql 语句拼接: …like “%” #{name} “%”

第4章:动态sql

动态sql: sql的内容是变化的,可以根据条件获取到不同的sql语句。主要是where部分发生变化。
动态sql的实现,使用的是MyBatis提供的标签, <if> 、<where>、<foreach>...
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。

准备工作:
	创建新的 maven 项目【ch06-dynamic-sql】,pom文件加入 mybatis、mysql 驱动依赖
	创建实体类 Student 、StudentDao 接口、StudentDao.xml、 mybatis.xml , 测试类
	使用之前的表 student。
	
	(可直接复制之前的项目)  

在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等符号,
[最好]将其转换为实体符号。否则,XML 可能会出现解析出错问题。
特别是对于小于号(<),在 XML 中是[绝不能]出现的。否则解析 mapper 文件会出错。
	
	实体符号表:
	-----------------------------
	<	小于		&lt;
	>	大于		&gt;
	>=	大于等于	&gt;=
	<=	小于等于	&lt;=
	-----------------------------

1、< if > 判断条件

  • 语法:
    < if test=“条件(使用参数java对象的属性值作为判断条件)”>
       sql 语句的部分
    < /if>

    对于该标签的执行,当 test属性的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。

接口方法:
	List<Student> selectStudentIf(Student student);

mapper文件:
    <select id="selectStudentIf" resultType="com.yuming.entity.Student">
		select id ,name, email ,age from student
		where id > 0
		<if test="name !=null and name != '' ">
	    	and name = #{name}
		</if>
		<if test="age > 0">
	    	or age > #{age}
		</if>
    </select>

测试方法:
    @Test
    public void testSelectStudentById() {
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao = sqlSession.getMapper(StudentDao.class); //动态获取接口的实现类对象

		//查找姓名是“李四”或者 年龄大于 40 的
		Student student = new Student();
		student.setName("李四");
		student.setAge(40);
		List<Student> studentList = dao.selectStudentIf(student);

		studentList.forEach(stu -> System.out.println(stu));
		sqlSession.close();
    }

结果:
	student{id=1002, name='李四', email='lisi@qq.com', age=25}
	student{id=1003, name='王五', email='123@163.com', age=50}
	student{id=1022, name='tom2', email='123@163.com', age=52}

2、< where>

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

  • 语法:
    < where>
       其他动态 sql语句 < if> < if>…
    < /where>

  • 只使用< if/>标签时,存在一个比较麻烦的地方:
       需要在 where 后手工添加类似于 1=1 的永为真子句。
       因为,若 where后的所有条件均为 false,而 where后若又没有永为真子句,
       则SQL中就会只剩下一个空的where,SQL出错。
       所以,在 where后,需要添加永为真子句 1=1,以防止这种情况的发生。
       但当数据量很大时,会严重影响查询效率。

  • 使用< where/>标签:
       在有查询条件时,可以自动添加上 where 子句;
       没有查询条件时,不会添加where 子句。
       需要注意的是,第一个< if/>标签中的 SQL 片段,可以不包含 and。
       不过,写上 and 也不错,系统会将多出的 and 去掉。
       但其它< if/>中 SQL 片断的 and 或者 or,必须要求写上。否则 SQL 语句将拼接出错。

<select id="selectStudentWhere" resultType="com.yuming.entity.Student">
	select id ,name, email ,age from student
	<where>
    	<if test="name !=null and name != '' ">
	 		name = #{name}
    	</if>
    	<if test="age > 0">
			or age > #{age}
    	</if>
	</where>
</select>

3、< foreach>

  • < foreach> 是循环java中的数组、list集合的。 主要用在sql的in语句中

    语法:
       < foreach collection=" " item=" " open=" " close=" " separator=" ">
          #{xxx}
       < /foreach>

  • foreach中的几个属性:
       collection: 表示接口中的方法参数的类型。数组用array, list集合用list
       item: 自定义的,表示数组和集合成员的变量
       open: 循环开始时的字符
       close: 循环结束时的字符
       separator: 集合成员之间的分隔符

  • 示例: 查询学生id是 1001,1002,1003的学生信息
       select * from student where id in (1001,1002,1003)

  • (1) 遍历 List<简单类型>

1)接口方法:
	List<Student> selectForeachOne(List<Integer> idlist);

2)mapper文件:
	<select id="selectForeachOne" resultType="com.yuming.entity.Student">
		select * from student where id in
		<foreach collection="list" item="myid" open="(" close=")" separator=",">
			#{myid}
		</foreach>
	</select>

    或者:
	<select id="selectForeachOne" resultType="com.yuming.entity.Student">
		select * from student
		<if test="list != null and list.size > 0">
		    where id in
		    <foreach collection="list" item="stuid" open="(" close=")" separator=",">
				#{stuid}
		    </foreach>
		</if>
	</select>
	
3)测试方法:
	@Test
	public void testSelectForEach(){
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao  =  sqlSession.getMapper(StudentDao.class); 

		List<Integer> list = new ArrayList<>(); // List<简单类型>
		list.add(1001);
		list.add(1002);
		list.add(1003);

		//查询学生id是 1001,1002,1003的学生信息
		List<Student> students = dao.selectForeachOne(list);
		for(Student stu:students){
		    System.out.println("查询结果:"+stu);
		}
	}
  • (2) 遍历 List<对象类型>
1)接口方法
	List<Student> selectForeachTwo(List<Student> stulist);

2)mapper文件
	<select id="selectForeachTwo" resultType="com.yuming.entity.Student">
	    select * from student where id in
	    <foreach collection="list" item="stu" open="("  close=")" separator=",">
		     #{stu.id}
	    </foreach>
	</select>
	
	可以灵活的拼接 动态sql:
	<select id="selectForeachTwo" resultType="com.yuming.entity.Student">
	    select * from student where id in(
	    <foreach collection="list" item="stu" separator=",">
			#{stu.id}
	    </foreach>
	    )
	</select>

3)测试方法:
	@Test
	public void testSelectForTwo(){
	    SqlSession sqlSession = MyBatisUtil.getSqlSession();
	    StudentDao dao  =  sqlSession.getMapper(StudentDao.class);

	    List<Student> stuList  = new ArrayList<>(); // List<对象类型>
	    Student s1 = new Student();
	    s1.setId(1002);
	    s1.setName("lisi");
	    stuList.add(s1);  //将s1对象添加到list集合

	    Student s2 = new Student();
	    s2.setId(1003);;
	    s2.setName("zs");
	    stuList.add(s2); //将s2对象添加到list集合

	    List<Student> students = dao.selectForeachTwo(stuList);
	    for(Student stu:students){
		System.out.println("查询结果:"+stu);
	    }
	}

4、< sql>代码片段

  • < sql>标签用于定义 SQL 片断,以便其它 SQL 标签复用。
    而其它标签使用该 SQL 片断,需要使用< include/>子标签。
    该< sql>标签可以定义 SQL 语句中的任何部分,所以< include/>子标签可以放在动态 SQL的任何位置

    步骤:
       1.先定义:< sql id=“自定义名称唯一”> sql语句、表名、字段等 </ sql>
       2.再使用:< include refid=“id的值” />

例如:

<select id="selectForeachTwo" resultType="com.yuming.entity.Student">
	select * from student where id in
	<foreach collection="list" item="stu" open="("  close=")" separator=",">
		#{stu.id}
	</foreach>
</select>

同等的写法:

① 先定义<sql>代码片段:
<sql id="mysqlOne">
    select id ,name, email ,age from student
</sql>

② 再通过<include/>使用代码片段
<select id="selectForeachTwo" resultType="com.yuming.entity.Student">

	<include refid="mysqlOne" />    where id in

	<foreach collection="list" item="stu" open="("  close=")" separator=",">
		#{stu.id}
	</foreach>
</select>

第5章:MyBatis 配置文件

1、主配置文件

  • MyBatis 的主配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
    之前项目中使用的 mybatis.xml 是主配置文件。

  • 主配置文件特点:

  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">
  1. 根元素,< configuration> < /configuration>,主要包含标签:
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
      environment(环境变量)
       transactionManager(事务管理器)
       dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)

主要使用的有:
< settings>—————————加入日志配置,可以在控制台输出执行的 sql 语句和参数
< typeAliases>——————设置类型别名
< environments>—————配置数据库的连接信息(数据源)
< mappers>——————————指定sql mapper(sql映射文件)的位置
  …

注:更多详情可以看mybatis的参考文档

2、事务管理器

事务管理器<transactionManager type="JDBC"/>

transactionManager:  是mybatis提交事务、回滚事务的方式

该标签用于指定MyBatis所使用的事务管理器。MyBatis支持两种事务管理器类型:JDBC 与MANAGED。
	1)JDBC:使用 JDBC 的事务管理机制。即,通过 Connection 的 commit()方法提交,通过 rollback()方法回滚。
		但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。
		即程序中需要显式的对事务进行提交或回滚。从日志的输出信息中可以看到:“autocommit to false”

			Created connection 282828951.
			Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@10dba097]
			==>  Preparing: select id ,name, email ,age from student where id in ( ? , ? ) 

	2)MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。

自动提交事务:
	设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。
		SqlSession openSession();
		SqlSession openSession(boolean autoCommit);
	有参数为 true,使用自动提交:
		SqlSession sqlSession = factory.openSession(true);
	再执行 insert 操作,无需执行 session.commit(), 事务是自动提交的

3、dataSource 数据源

dataSource: 表示数据源。
	在 Mybatis 的主配置文件中,通过<dataSource type="POOLED"> 来实现 Mybatis 中连接池的配置。
	java体系中,规定实现了javax.sql.DataSource接口的都是数据源。  数据源表示Connection对象的。

dataSource的类型
	1)POOLED:	使用连接池, mybatis会创建PooledDataSource类
	2)UPOOLED:	不使用连接池, 在每次执行sql语句,先创建连接,执行sql,再关闭连接
				mybatis会创建一个UnPooledDataSource,管理Connection对象的使用
	3)JNDI:	使用 JNDI 实现的数据源 

dataSource 配置:
	<dataSource type="POOLED">
		<!-- 连接数据库的四个要素 -->
		<property name="driver"   value="com.mysql.jdbc.Driver"/>
		<property name="url"	  value="jdbc:mysql://localhost:3306/sjk"/>
		<property name="username" value="root"/>
		<property name="password" value="123456"/>
	</dataSource>

4、数据库属性配置文件

为了方便对数据库连接的管理,DB 连接四要素数据一般都是存放在一个专门的属性文件中的。
MyBatis主配置文件需要从这个属性文件中读取这些数据。

目的:	把数据库连接信息放到一个单独的文件中,和MyBatis主配置文件分开。
	便于修改,保存,处理多个数据库的信息。

1)在resources目录中定义一个属性配置文件, xxxx.properties, 例如 jdbc.properties
	在属性配置文件中, 定义数据,格式是 key=value 
	key 一般使用 . 做多级目录的。
		jdbc.driver=com.mysql.jdbc.Driver
		jdbc.url=jdbc:mysql://localhost:3306/sjk
		jdbc.username=root
		jdbc.password=123456

2)使用 properties  标签
	修改主配置文件,文件开始位置加入:
	
	<!--指定properties文件的位置,从类路径根(target/clasess)开始找文件-->
	<properties resource="jdbc.properties" />

3)在MyBatis的主配置文件中,使用 key指定值, ${key}

	<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>

5、typeAliases(类型别名)

Mybatis 支持默认别名,我们也可以采用自定义别名方式来开发,主要使用在<select resultType=”别名”>
mybatis.xml 主配置文件定义别名:

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

		<!--
		  第二种方式
		  <package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)
		-->
		<package name="com.yuming.domain"/>
		<package name="...其他包"/>
	</typeAliases>

mapper.xml 文件,使用别名表示类型
	<select id="selectStudents" resultType="Student2">
		select id,name,email,age from student
	</select>

在这里插入图片描述

6、mappers(映射器)

mappers 用于指定sql mapper(sql映射文件)的位置

<mappers>
    <!--第一种方式:指定多个mapper文件-->
    <!--<mapper resource="com/yuming/dao/StudentDao.xml"/>
        <mapper resource="com/yuming/dao/OrderDao.xml" />-->

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

7、一个完整的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文件的位置。编译前创建在src/main/resources下面,
        编译后从类路径根(target/clasess)开始找文件-->
    <properties resource="jdbc.properties"/>

    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--加入日志配置,可以在控制台输出执行的 sql 语句和参数-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>

    <!--定义 类型别名-->
    <typeAliases>
        <!-- 第一种方式:    一个类型指定一个自定义别名
                    type:自定义类型的全限定名称;  alias:别名(短小,容易记忆的)   -->
        <!--<typeAlias type="com.yuming.entity.Student" alias="stu" />
            <typeAlias type="com.yuming.entity.Student2" alias="stu2"/>-->

        <!--第二种方式:
            使用<package> ,name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)  -->
        <package name="com.yuming.entity"/>
    </typeAliases>

    <!--配置分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor" />
    </plugins>

    <!--数据库的环境配置
        default必须和下面某一个environment的id值一样。告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库 -->
    <environments default="myFirst">
        <!-- environment : 一个数据库信息的配置环境。id:一个唯一值,自定义,表示环境的名称。-->
        <environment id="myFirst">
            <!-- 配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚) -->
            <transactionManager type="JDBC"/>
            <!--数据源的类型: POOLED 表示使用数据库的连接池-->
            <dataSource type="POOLED">
                <property name="driver"	  value="${jdbc.driver}"/> <!-- 使用 jdbc.properties 文件 :  语法 ${key}-->
                <property name="url"	  value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

        <environment id="mySecond">  <!--可以配置多个数据库环境-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver"	  value="com.mysql.jdbc.Driver"/>
                <property name="url"      value="jdbc:mysql://127.0.0.1:3306/onlinedb"/>
                <property name="username" value="root"/>
                <property name="password" value="123123"/>
            </dataSource>
        </environment>

    </environments>


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

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

</configuration>

jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/zt
jdbc.username=root
jdbc.password=123456

第6章:PageHelper 分页

  • PageHelper 是做数据分页的
    PageHelper 是 Mybatis 通用分页插件,支持多种数据库:Oracle、Mysql、 SqlServer(2005,2008)…

  • 实现步骤:

  • (1)pom文件中加入 maven 坐标(依赖)

<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.1.10</version>
</dependency>
  • (2)主配置文件加入 plugin 插件配置
    在< environments> 之前加入:
<!--配置插件-->
<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
  • (3)使用 PageHelper 对象
    在查询语句之前调用 PageHelper.startPage 静态方法
    除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。
    在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,
    紧跟在这个方法后的第一个 MyBatis 查询方法会被进行分页。
接口方法:
	List<Student> selectAll();

mapper 文件:
	<select id="selectAll" resultType="com.yuming.entity.Student">
	    select * from student order by id
	</select>

测试方法:
	@Test
	public void testSelectAllPageHelper(){
		SqlSession sqlSession = MyBatisUtil.getSqlSession();
		StudentDao dao  =  sqlSession.getMapper(StudentDao.class);

		//加入PageHelper的方法,分页
		// pageNum: 第几页, 从1开始
		// pageSize: 一页中有多少行数据
		PageHelper.startPage(2,3);// 获取第 2 页,3 条内容 (所有数据中的第4、5、6条)

		List<Student> students = dao.selectAll();
		for(Student stu:students){
		    System.out.println("结果:"+stu);
		}
		sqlSession.close();
	}

【思维导图】

在这里插入图片描述

传送门

上一章:框架 - Maven入门
下一章:框架 - Spring框架

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页