Maven项目整合MyBatis、Spring、Springmvc

一、MyBaits

1. MyBatis简介(了解)

1.1. 什么是MyBatis
MyBatis 本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、 preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
总之,Mybatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决JDBC将结果集封装为Java对象的麻烦。
下图是MyBatis架构图:
在这里插入图片描述
(1)mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂
(2)基于SqlSessionFactory可以生成SqlSession对象
(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。
(4)Executor是SqlSession底层的对象,用于执行SQL语句
(5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)

1.2. 为什么要使用MyBatis
思考:在开始之前,思考下如何通过JDBC查询Emp表中的所有记录,并封装到 一个List集合中返回。(演示:准备数据、导包、导入JDBC程序)
1、使用传统方式JDBC访问数据库:
(1)使用JDBC访问数据库有大量重复代码(比如注册驱动、获取连接、获取传输器、释放资源等);
(2)JDBC自身没有连接池,会频繁的创建连接和关闭连接,效率低;
(3)SQL是写死在程序中,一旦修改SQL,需要对类重新编译;
(4)对查询SQL执行后返回的ResultSet对象,需要手动处理,有时会特别麻烦;
2、使用mybatis框架访问数据库:
(1)Mybatis对JDBC对了封装,可以简化JDBC代码;
(2)Mybatis自身支持连接池(也可以配置其他的连接池),因此可以提高程序的效率;
(3)Mybatis是将SQL配置在mapper文件中,修改SQL只是修改配置文件,类不需要重新编译。
(4)对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象。

总之,JDBC中所有的问题(代码繁琐、有太多重复代码、需要操作太多对象、释放资源、对结果的处理太麻烦等),在Mybatis框架中几乎都得到了解决!!

2. MyBatis快速入门

2.1. 准备数据

-- 1、创建数据库 yonghedb 数据库 
create database if not exists yonghedb charset utf8; use yonghedb; -- 选择yonghedb数据库
-- 2、删除emp表(如果存在) 
drop table if exists emp;
-- 3、在 yonghedb 库中创建 emp 表 
create table emp( id int primary key auto_increment, name varchar(50), job varchar(50), salary double );
-- 4、往 emp 表中, 插入若干条记录
...

2.2. 创建工程,准备开发环境
创建工程,导入所需jar包、创建测试类
1、创建Maven的java工程
2、导入junit、mysql、mybaits、log4j等开发包

<dependencies>
 <!-- junit单元测试 -->
<dependency> 
<groupId>junit</groupId> <artifactId>junit</artifactId> 
<version>4.9</version>
 </dependency>
  <!-- mysql驱动 -->
<dependency>
 <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> 
  </dependency> 
  <!-- mybatis -->
<dependency> 
<groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.8</version> 
</dependency> 
<!-- 整合log4j -->
<dependency> 
<groupId>org.slf4j</groupId> 
<artifactId>slf4j-log4j12</artifactId> <version>1.6.4</version> 
</dependency> 
</dependencies>

3、创建com.tedu.mybatis.TestMybatis01测试类,并提供findAll方法(查询emp表中所有的员工信息),开发步骤如下:

/** 练习1(快速入门): 查询emp表中的所有员工, 返回一个List<Emp>集合 * @throws IOException */ 
@Test 
public void findAll() throws IOException {
   
    
//1.读取mybatis的核心配置文件(mybatis-config.xml) 
//2.通过配置信息获取一个SqlSessionFactory工厂对象 
//3.通过工厂获取一个SqlSession对象 //4.通过namespace+id找到要执行的sql语句并执行sql语句 
//5.输出结果 }

2.3. 添加mybatis-config.xml文件
1、在src/main/resources目录下,创建mybatis-config.xml文件(MyBatis的核心配置文件)
在这里插入图片描述
2、mybatis-config.xml文件配置如下:
mybatis-config文件头信息如下:

<?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"> 
 <!-- MyBatis的全局配置文件 -->
<configuration > 

</configuration>

mybatis-config文件详细配置如下:

<?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"> 
 <!-- MyBatis的全局配置文件 -->
<configuration > 
<!-- 1.配置环境,可配置多个环境(比如:develop开发、test测试) -->
<environments default="develop"> 
<environment id="develop"> 
<!-- 1.1.配置事务管理方式:JDBC/MANAGED JDBC:将事务交给JDBC管理(推荐) MANAGED:自己管理事务
-->
<transactionManager type="JDBC"></transactionManager> <!-- 1.2.配置数据源,即连接池 JNDI/POOLED/UNPOOLED JNDI:已过时 POOLED:使用连接池(推荐) UNPOOLED:不使用连接池
-->
<dataSource type="POOLED"> 
<property name="driver" value="com.mysql.jdbc.Driver"/> 
<property name="url" value="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8"/> 
<property name="username" value="root"/> 
<property name="password" value="root"/> </dataSource> 
</environment> 
</environments> 
<!-- 2.导入Mapper配置文件,如果mapper文件有多个,可以通过多个mapper标 签导入 -->
<mappers>
 <mapper resource="EmpMapper.xml"/> 
 </mappers>
</configuration>

2.4. 添加EmpMapper.xml文件
1、在src/main/resources目录下,创建EmpMapper.xml文件 (实体类的映射文件)
在这里插入图片描述
2、EmpMapper.xml文件配置如下:
EmpMapper文件头信息如下:

<?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值应该保证唯一 在程序中通过[ namespace + id ]定位到要执行哪一条SQL语句
-->
<mapper namespace=""> 
</mapper>

EmpMapper文件详细配置如下:

<?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值应该保证唯一 在程序中通过[ namespace + id ]定位到要执行哪一条SQL语句
-->
<mapper namespace="EmpMapper"> 
<!-- 通过select、insert、update、delete标签声明要执行的SQL -->
<!-- 练习1: 查询emp表中的所有员工信息 resultType指定查询的结果将会封装到什么类型中 即使最终返回的结果是集合(List<Emp>),resultType也只需要指定集合中的泛 型即可!
-->
<select id="findAll" resultType="com.tedu.pojo.Emp"> select * from emp 
</select>
</mapper>

2.5. 添加并编写Emp实体类
注意:在当前实例中,Emp类中的属性和数据库表的字段名称必须一致,否则将会无法将结果集封装到Java对象中。
在src/main/java目录下创建 com.xxx.pojo.Emp类,并编辑Emp类:提供私有属性以及对应的getter方法、setter方法,并重写toString方法

package com.tedu.pojo;
 /*** 实体类,用于封装Emp表中的一条用户信息 */ 
 public class Emp {
   
    
 //1.声明实体类中的属性 
 private Integer id; 
 private String name; 
 private String job; 
 private Double salary; 
 //2.提供对应的getter和setter方法 
 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 getJob() {
   
    
  return job; 
  }
  public void setJob(String job) {
   
    
  this.job = job; 
  }
  public Double getSalary() {
   
    
  return salary; 
  }
  public void setSalary(Double salary) {
   
   
   this.salary = salary; 
   }
   //3.重写toString方法 
   @Override 
   public String toString() {
   
   
    return "Emp [id=" + id + ", name=" + name + ", job=" + job + ", salary=" + salary + "]"; 
    } 
    }

2.6. 实现测试类,并测试
1、实现findAll方法,代码如下:

/** 练习1(快速入门): 查询emp表中的所有员工, 返回一个List<Emp>集合 * @throws IOException */ 
@Test 
public void findAll() throws IOException {
   
    
//1.读取mybatis的核心配置文件(mybatis-config.xml) 
InputStream in = Resources .getResourceAsStream("mybatis-config.xml");
 //2.通过配置信息获取一个SqlSessionFactory工厂对象 
 SqlSessionFactory fac = new SqlSessionFactoryBuilder().build( in ); 
 //3.通过工厂获取一个SqlSession对象 
 SqlSession session = fac.openSession(); 
 //4.通过namespace+id找到要执行的sql语句并执行sql语句 
 List<Emp> list = session .selectList("EmpMapper.findAll");
  //提交事务 
  session.commit();
 
 //5.输出结果
for(Emp e : list) {
   
    System.out.println( e );
 } 
 }

2、执行findAll方法,输出结果

2.7. 加入log4j日志框架

# Global logging configuration log4j.rootLogger=DEBUG, stdout 
# Console output... 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

mybatis默认使用log4j作为输出日志信息。
只要将该文件放在指定的位置,log4j工具会自动到指定位置加载上述文件,读取文件中的配置信息并使用!

3. MyBatis入门细节

3.1. mybatis-config.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"> 
 <!-- MyBatis的全局配置文件 -->
<configuration > 

</configuration>

mybatis-config文件详细配置如下:

<?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"> 
 <!-- MyBatis的全局配置文件 -->
<configuration > 
<!-- 1.配置环境,可配置多个环境(比如:develop开发、test测试) -->
<environments default="develop"> 
<environment id="develop"> 
<!-- 1.1.配置事务管理方式:JDBC/MANAGED JDBC:将事务交给JDBC管理(推荐) MANAGED:自己管理事务
-->
<transactionManager type="JDBC"></transactionManager> <!-- 1.2.配置数据源,即连接池 JNDI/POOLED/UNPOOLED JNDI:已过时 POOLED:使用连接池(推荐) UNPOOLED:不使用连接池
-->
<dataSource type="POOLED"> 
<property name="driver" value="com.mysql.jdbc.Driver"/> 
<property name="url" value="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8"/> 
<property name="username" value="root"/> 
<property name="password" value="root"/> </dataSource> 
</environment> 
</environments> 
<!-- 2.导入Mapper配置文件,如果mapper文件有多个,可以通过多个mapper标 签导入 -->
<mappers>
 <mapper resource="EmpMapper.xml"/> 
 </mappers>
</configuration>

environments 标签:该标签内部可以配置多个environment,即多种环境,每种环境可以做不同配置或连接不同数据库。例如,开发、测试、生产环境可能需要不同的配置,连接的数据库可能也不相同,因此我们可以配置三个environment,分别对应上面三种不同的环境。
但是要记住,environment可以配置多个,但是最终要使用的只能是其中一个!
environment 标签:内部可以配置多种配置信息,下面介绍事务管理配置和数据源配置。
transactionManage 标签:事务管理配置,mybatis中有两种事务管理方式,也就是
type="[JDBC|MANAGED]。
**JDBC:这个配置就是直接使用了 JDBC的提交和回滚设置,它依赖于从数据源得到的连 接来管理事务范围。推荐使用。 **
MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。需要自己手动添加并 管理。不推荐使用
JNDI:已过时,不推荐使用!
POOLED:使用连接池,mybatis会创建连接池,并从连接池中获取连接访问数据库,在 操作完成后,将会把连接返回连池。
UNPOOLED:不使用连接池,该方式适用于只有小规模数量并发用户的简单应用程序上。

mappers 标签:用于导入mapper文件的位置,其中可以配置多个mapper,即可以导入多个mapper文件。

3.2. EmpMapper.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值应该保证唯一 在程序中通过[ namespace + id ]定位到要执行哪一条SQL语句
-->
<mapper namespace="EmpMapper"> 
<!-- 通过select、insert、update、delete标签声明要执行的SQL -->
<!-- 练习1: 查询emp表中的所有员工信息 resultType指定查询的结果将会封装到什么类型中 即使最终返回的结果是集合(List<Emp>),resultType也只需要指定集合中的泛 型即可!
-->
<select id="findAll" resultType="com.tedu.pojo.Emp"> select * from emp 
</select>
</mapper>

(1)第1行是xml的文档声明,用于声明xml的版本和编码
(2)第2、3、4行,引入了xml约束文档,当前xml文档将会按照mybatis-3- mapper.dtd文件所要求的规则进行书写。
(3)Mapper标签:根标签,其中namespace(名称空间,也叫命名空间),要求不能重复。在程序中通过【namespace + id 】定位到要执行哪一条SQL语句
(4)select标签:用于指定将来要执行的各种SQL语句。标签上可以声明属性,下面介绍常用的属性:id、resultType、resultMap
id属性:要求值不能重复。将来在执行SQL时,可以通过【namespace + id】找到指定SQL并执行。
resultType属性:从这条SQL语句中返回所期望类型的类的完全限定名称(包名+类名)。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。
简而言之,resultType控制查询SQL执行后返回值的类型或集合中的泛型,例如查询emp表中的单条记录,返回值是一个Emp对象,因此,
resultType=“com.xxx.pojo.Emp”;
如果查询emp表中的多条记录,返回值是一个List,此时resultType的值应该集合中的泛型,因此resultType=“com.xxx.pojo.Emp”;
resultMap属性:复杂对象结构(例如多表关联查询等)。 使用 resultType 或 resultMap,但不能同时使用。

4. MyBatis增删改查

1、编辑EmpMapper.xml文件

<!-- 练习02: 新增员工信息: 赵云 保安 6000 -->
	<insert id="testInsert02" >
		insert into emp value( null, '赵云', '保安', 6000 )
	</insert>
	
	<!-- 练习03: 修改员工信息:赵云 保镖 20000 -->
	<update id="testUpdate03">
		update emp set job='保镖', salary=20000 where name='赵云'
	</update>
	
	<!-- 练习04: 删除name为'赵云'的记录 -->
	<delete id="testDelete04">
		delete from emp where name='赵云'
	</delete>

2、编写TestMybatis类

//1.读取mybatis的核心配置文件(mybatis-config.xml)
		InputStream in = Resources.getResourceAsStream( "mybatis-config.xml" );
		//2.根据配置信息获取SqlSession工厂对象
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build( in );
		//3.通过SqlSession工厂获取一个SqlSession对象(打开与数据库的连接)
		SqlSession session = factory.openSession( true );  //true表示自动提交事务
		//4.1.新增员工信息: 赵云 保安 6000
		//int rows = session.insert( "EmpMapper.testInsert02" );
		//4.2.修改员工信息:赵云 保镖 20000
		//int rows  = session.update( "EmpMapper.testUpdate03" );
		//4.3.删除name为'赵云'的记录
		int rows = session.delete( "EmpMapper.testDelete04" );
		
		//session.commit(); //提交事务

5. mybatis中的占位符

5.1. #{}占位符
在上面的增删改查操作中,SQL语句中的值是写死在SQL语句中的,而在实际开发中,此处的值往往是用户提交过来的值,因此这里我们需要将SQL中写死的值替换为占位符。
在mybatis中占位符有两个,分别是 #{} 占位符 和 KaTeX parse error: Expected 'EOF', got '#' at position 12: {} 占位符: **#̲{}: 相当于JDBC中的问号…{} :是为SQL片段(字符串)进行占位,将传过来的SQL片段直接拼接在${} 占位符所在的位置,不会进行任何的转义处理。(由于是直接将参数拼接在SQL语句中,因此可能会引发SQL注入攻击问题)
需要注意的是:使用 ${} 占位符为SQL语句中的片段占位时,即使只有一个占位符,需要传的也只有一个参数,也需要将参数先封装再传递!**

练习:
在mapper文件中编写SQL语句:

<!-- 练习05: 查询emp表中指定id的员工信息 -->
	<select id="findById05"  resultType="com.tedu.pojo.Emp">
		select * from emp where id=#{
   
   id}
	</select>
	
	<!--练习06:新增员工信息:张飞Java工程师 15000  -->
	<insert id="insert06">
	insert into emp value(null,#{
   
   name},#{
   
   job},#{
   
   salary})
	</insert>
	
	<!-- 练习07:修改员工信息:张飞架构师 25000 -->
	<update id="update07">
	update emp set job=#{
   
   job},salary=#{
   
   salary}
	where name=#{
   
   name}
	</update>
	
	<!--练习08:根据条件查询emp表中的员工信息  -->
	<select id="findAll08" resultType="com.xxx.pojo.Emp">
	select * from emp ${
   
   sqlStr}
	</select>
	
	<delete id="delete09">
	delete from emp where id=#{
   
   id}   <!--如果id=${
   
   id} 会出现注入攻击,删除全部  -->
	</delete>

Java代码实现:

SqlSession session;
	@Before
	public void init() throws IOException {
   
   
		//1.读取mybatis的核心配置文件(mybatis-config.xml)
		InputStream in = Resources.getResourceAsStream( "mybatis-config.xml" );
		//2.根据配置信息获取SqlSession工厂对象
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build( in );
		//3.通过SqlSession工厂获取一个SqlSession对象(打开与数据库的连接)
		session = factory.openSession( true );  //true
	}
	
	//=============== mybatis中的占位符 ===============
	
	/** 练习05: 查询emp表中指定id的员工信息 */
	@Test
	public void testFindById05() {
   
   
		Integer id = 8;
		Emp emp = session.selectOne( "EmpMapper.findById05", id );
		System.out.println( emp );
	}
	
	/* 练习06:新增员工信息:张飞Java工程师 15000
	 * 如果SQL语句有多个占位符,就需要传递多个参数,多参数如何传递
	 * 1》通过map集合进行封装(通用)
	 * 2》通过PoJo对象进行封装
	 *  */
	@Test
	public void testInsert06() {
   
   
		/*
		 * //声明一个Map集合,将SQL参数封装到Map集合中
		 *  Map<String,Object> map = new HashMap<>();
		 * map.put("name","张飞"); 
		 * map.put("job","Java开发工程师"); 
		 * map.put("salary",15000);
		 * session.insert("EmpMapper.insert06",map);
		 */
		
		//声明一个Emp对象,将参数封装到Emp对象中
		Emp emp =new Emp();
		emp.setName("关羽");
		emp.setJob("士兵");
		emp.setSalary(20000d);
		session.insert("EmpMapper.insert06",emp);
		
	}
	
	/* 练习07:修改员工信息:张飞架构师 25000 */
	@Test
	public void testUpdate07() {
   
   
		//声明一个map集合,将SQL参数封装到map集合中
		Map<String,Object> map=new HashMap<>();
		map.put("name","张飞");
		map.put("job","架构师");
		map.put("salary",25000d);
		session.update("EmpMapper.update07",map);
	}
	
	
	/*练习08:根据条件查询emp表中的员工信息*/
	@Test
	public void testFindAll08() {
   
   
		Map<String,Object> map=new HashMap<String,Object>();
//		map.put("sqlStr","where salary>3500");
		map.put("sqlStr","where name like '刘%'");
		
		List<Emp> list = session.selectList("EmpMapper.findAll08",map);
		for(Emp emp:list) {
   
   
			System.out.println(emp);
		}
	}
	
	@Test
	public void testDelete09() {
   
   
		Map map=new HashMap();
		map.put("id","1 or 1=1");
		session.delete("EmpMapper.delete09",map);
	}

在上面的增删改查练习中,当SQL语句中包含的参数值是传递过来的,在SQL语句中我们会通过 #{} 占位符进行占位,在SQL语句真正执行时,再将传递过来的值替换SQL语句中的占位符。
其实, #{} 就是JDBC中的问号(?)占位符,因此为了安全考虑,在执行时会对传递过来的字符串和日期类型高的值进行转译处理。
例如:查询指定name的员工信息,SQL语句为:
select * from emp where name=#{name}
其实就等价于JDBC中: select * from emp where name=? ,
如果传过来的参数值为:张三,那么最终执行的SQL语句为:
– 在参数替换占位符的同时进行了转义处理(在值的两边加上了单引号)
select * from emp where name=‘张三’

5.2. ${}占位符
那么如果我们在传递的时候不是一个参数值,而是一个SQL片段呢?
例如:在查询时,我们想动态的传递查询的列:select #{columns} from emp
此时传递过来的应该是一个SQL片段,不同于上面的参数值,如果此时还用 # {} ,也会像上面一样被转译处理: select ‘id,name,job’ from emp ,这不是我们希望看到的!
如果不想让传过来的SQL片段被转译处理,而是直接拼接在SQL语句中,那么这里可以使用 ${} ,例如:
select ${columns} from emp
拼接之后: select id,name,job from emp
练习:
在mapper文件中编写SQL语句:

<!-- 练习9: 动态指定要显示的列 -->
<select id="findAll2" resultType="com.tedu.pojo.Emp"> 
select ${
   
   cols
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值