Java持久层之MyBatis:01_MyBatis入门


原生JDBC访问数据库

  • JDBC是SUN公司提出的一些列规范:而具体的实现是由各个数据库厂商来实现的:因为各个数据库都有其特殊性:所以规范是没有办法确定其实现的:JDBC是一种桥接模式
  • JDBC操作数据库的步骤:

(1) 注册数据库驱动
(2) 获取数据库连接对象
(3) 准备SQL语句
(4) 获取执行SQL语句的Statement对象
(5) 执行SQL语句
(6) 处理结果
(7) 关闭相关资源

// 1. 注释数据库驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());

// 2. 获取数据库连接对象:Connection对象
String url = "jdbc:mysql://localhost:3306/clight";
String username = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, username, password);

// 3. 准备SQL语句
String sql = "select * from t_user";

// 4. 得到指向SQL语句的Statement对象
PreparedStatement pstmt = connection.prepareStatement(sql);

// 5. 发送SQL语句给数据库服务器
ResultSet rs = pstmt.executeQuery();

// 6. 处理结果
while (rs.next()) {
	String id = rs.getString("id");
	String name = rs.getString("username");
	String pwd = rs.getString("password");
	System.out.println(id + ": " + name + "--" + pwd);
	System.out.println("--------------------------------");
}

// 7. 关闭资源
if (rs != null) {
	rs.close();
}
if (pstmt != null) {
	pstmt.close();
}
if (connection != null) {
	connection.close();
}
  • 数据库:采用mysql

原生JDBC访问数据库存在的问题

  • 数据库连接,使用时就创建,不使用立即释放:对数据库进行频繁连接开启与关闭,造成数据库资源浪费,影响数据库性能:解决方案:使用数据库连接池管理数据库连接
  • 将SQL语句硬编码到Java代码中,如果将来SQL语句需要修改,那么需要重新编译Java代码:不利于系统维护!解决方案:将SQL语句配置在XML配置文件中,即使SQL语句发生变化,也不需要对Java代码进行重新编译
  • 向PreparedStatement中设置参数,对占位符位置和设置参数值,硬编码在Java代码中,不利于系统维护!解决方案:将SQL语句以及占位符和参数全部配置在XML文件中
  • 从ResultSet中遍历结果集数据时,存在硬编码:获取表的字段进行硬编码,不利于系统维护!解决方案:将查询的结果集自动映射为Java对象

ORM模型

  • ORM:Object Realational Mapping:对象关系映射:数据库表中的记录简单Java对象POJO(Plain Ordinary Java Object)的映射关系模型
  • 对象模型:Java代码中的实体类对象
  • 关系模型:数据表中的记录
  • 所有的ORM模型都是对底层JDBC的封装:不同的ORM模型对JDBC的封装程度不一样

MyBatis框架原理

在这里插入图片描述


搭建MyBatis开发环境

  • 第一步:创建项目:JavaSE项目或JavaEE项目均可:因为MyBatis是持久层框架
    在这里插入图片描述

  • 第二步:导 包
    (1)MyBatis核心包
    在这里插入图片描述
    (2)MyBatis依赖包
    在这里插入图片描述
    (3)数据库驱动包
    在这里插入图片描述

  • 第三步:创建实体类
    在这里插入图片描述

package com.ycom.mybatis.entity;

import java.util.Date;

public class User {
	// 实体类属性要求: 属性与数据表的字段对应
	private int id;
	private String username;
	private Date birthday;
	private String sex;
	private String address;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
}

在这里插入图片描述

  • 第四步:编写映射配置文件:映射配置文件的位置与名称没有固定要求,但是映射配置文件的名称一般都是有约定的:基于MyBatis原生的DAO开发模式下的映射配置文件的名称为:实体类名称.xml,例如User.xml;基于Mapper代码的开发模式下的映射文件的名称为:实体类名+Mapper.xml,例如UserMapper.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属性: 对SQL进行分类化管理
	(1) MyBatis原生DAO开发模式: 可以随便起名称
	(2) 基于Mapper代理开发模式: namespace属性的值是有要求的: 有特殊重要的作用
-->
<mapper namespace="test">
	<!-- 
		id属性:用来标识映射配置文件中的SQL语句
			     将SQL语句封装到MappedStatement对象中:称之为statement的id
		
		parameterType属性:指定输入参数类型,这里指定int类型
		resultType属性:指定SQL输出结果的所映射的Java实体类对象的类型
					 select指定resultType表示将单条记录映射成Java对象
					 
		#{}表示站位符
		#{id}中的id表示接收输入的参数,参数名称就是id
		如果输入参数类型是基本类型,那么#{}中的参数可以是任意的,可以是value或者其他
	-->
	<select id="findUserById" parameterType="int" resultType="com.ycom.mybatis.entity.User">
		select * from user where id=#{value}
	</select>
	
</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>
	<!-- 第一部分: 配置数据源 -->
	<!-- 与Spring整合后 environments配置都将废除-->
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" /><!-- 使用JDBC事务管理: 事务控制由MyBatis管理-->
			<dataSource type="POOLED"><!-- 数据库连接池: 由MyBatis管理 -->
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
				<property name="username" value="root"/>
				<property name="password" value="root"/>
			</dataSource>
		</environment>
	</environments>
	
	<!-- 第二部分:加载映射配置文件 -->
	<mappers>
		<mapper resource="sqlmap/User.xml"/>
	</mappers>
</configuration>
  • 第六步: 编写Java代码
package com.ycom.mybatis.test;

import java.io.InputStream;

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 org.junit.Test;

import com.ycom.mybatis.entity.User;

public class MyBatisTest {
	@Test
	public void testQuery() throws Exception {
		// 1. 创建会话工厂: 传入全局配置文件
		String resource = "SqlMapConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		
		// 2. 得到会话对象
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		// 3. 通过sqlSession操作数据库
		User user = sqlSession.selectOne("test.findUserById", 1);
		
		System.out.println(user);
		
		// 释放资源
		sqlSession.close();
	}
}
  • 第七步:配置日志:在src模式下配置log4j.properties
# Global logging configuration
# 开发环境使用DEBUG,生产环境使用info
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入门案例

  • 案例描述:对用户表进行CRUD操作
    (1)根据用户id(主键)查询用户信息
    (2)根据用户名称进行模糊查询用户信息
    (3)添加用户
    (4)删除用户
    (5)更新用户
    在这里插入图片描述

项目的目录结构

在这里插入图片描述

在这里插入图片描述

根据用户id查询用户信息

  • 第一步:导包:MyBatis核心包与依赖包、数据库驱动包
  • 第二步:配置日志文件:db.properties
  • 第三步:配置全局配置文件:SqlMapConfig.xml:配置数据源
  • 第四步:创建实体类:User.java
  • 第五步:配置映射配置文件:User.xml
  • 第六步:配置全局配置文件:加载映射配置文件
  • 第七步:写代码:实现根据用户id查询用户信息
    在这里插入图片描述
  • 采用Debug模式调试代码,发现:SqlSession中的autoCommit=false,如果是进行数据库的更新操作,那么必须手动的进行commit操作
    在这里插入图片描述

根据用户名模糊查询用户信息

  • 第一步:导包:MyBatis核心包与依赖包、数据库驱动包
    在这里插入图片描述

  • 第二步:配置日志文件:db.properties
    在这里插入图片描述

  • 第三步:配置全局配置文件:SqlMapConfig.xml:配置数据源
    在这里插入图片描述

  • 第四步:创建实体类:User.java
    在这里插入图片描述

  • 第五步:配置映射配置文件:User.xml
    在这里插入图片描述

  • 第六步:配置全局配置文件:加载映射配置文件
    在这里插入图片描述

  • 第七步:写代码:根据用户名模糊查询用户信息
    在这里插入图片描述

  • 第八步:查看结果
    在这里插入图片描述

添加用户

一般的添加用户的过程

  • 映射配置文件
    在这里插入图片描述
  • 程序代码
    在这里插入图片描述
  • 注意:占位符#{}写的是实体类的属性名,不是成员变量名:但是正常情况下属性名就是成员变量名
    在这里插入图片描述

添加用户后获取自增长的主键值

  • 需求:添加用户的时候主键是自增长的,那么在添加用户之后能否获取新增的主键?
  • 获取主键的作用:在进行表关联操作的时候,在插入主表之后需要插入子表的操作,子表的外键值就是主表的主键值,此时就要获取主表的主键值:那么此时就需要自增主键的返回:主表的主键是子表的外键
    (1)MySQL自增长主键,执行insert提交之前自动生成一个自增长主键
    (2)通过MySQL函数获取刚插入记录的自增长主键:LAST_INSERT_ID()
    在这里插入图片描述
    (3)LAST_INSERT_ID()这个函数必须是在insert之后调用
  • 映射配置文件中的配置:
<!-- 3. 添加用户 -->
<insert id="addUser" 
		parameterType="com.ycom.mybatis.entity.User">
		<!--
			将插入的记录的主键返回:返回到User对象中
			SELECT LAST_INSERT_ID(): 得到刚刚insert操作的主键值: 注意:只适用于自增长主键
			keyProperty:将查询到的主键值设置到parameterType指定类型对象的哪个属性
			order:SELECT LAST_INSERT_ID()相对于insert语句的执行顺序
			resultType:指定SELECT LAST_INSERT_ID()结果的类型
		-->
		<selectKey keyProperty="uid" order="AFTER" resultType="java.lang.Integer">
			SELECT LAST_INSERT_ID()
		</selectKey>
		insert into user(username, address) values(#{name}, #{address})
</insert>
  • 代码实现:
@Test
public void testAddUser2() throws IOException {
	// 1. 创建会话工厂: 传入全局配置文件
	String resource = "SqlMapConfig.xml";
	InputStream inputStream = Resources.getResourceAsStream(resource);
	SqlSessionFactory sqlSessionFactory = 
			new SqlSessionFactoryBuilder().build(inputStream);
	
	// 2. 得到会话对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	
	// 3. 通过sqlSession操作数据库
	User user = new User();
	user.setUsername("Admin");
	user.setAddress("China");
	
	sqlSession.insert("user.addUser", user);
	System.out.println(user.getUid());
	
	sqlSession.commit();
	sqlSession.close();
}
//===========================================================================
// DEBUG [main] - ==>  Preparing: insert into user(username, address) values(?, ?) 
// DEBUG [main] - ==> Parameters: Admin(String), China(String)
// DEBUG [main] - <==    Updates: 1
// DEBUG [main] - ==>  Preparing: SELECT LAST_INSERT_ID() 
// DEBUG [main] - ==> Parameters: 
// DEBUG [main] - <==      Total: 1
// 32

在这里插入图片描述

添加用户后获取uuid的主键值

  • 使用uuid作为主键前提必须修改主键的类型为字符串
  • 执行思路
    (1) 先通过MySQL的函数uuid()查询到主键,其实就是生成一个uuid的主键:SELECT UUID()
    (2) 将拿到的uuid作为insert操作的主键值给赋值进去:必须在数据库客户端完成,因为MySQL是不能在插入记录的时候自动生成uuid()的
    (3) 结论SELECT UUID()必须是在INSERT语句之前比执行,得到结果作为INSERT语句中的VALUES值
  • 创建一张表:t_user
CREATE TABLE t_user(
	id VARCHAR(50) PRIMARY KEY,
	username VARCHAR(50),
	age INT 
)CHARSET utf8;
  • 创建一个实体类:User
package com.ycom.mybatis.entity;

public class User2 {
	private String id;
	private String username;
	private int age;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}
  • 编写映射配置文件
	
<insert id="addUser2" parameterType="com.ycom.mybatis.entity.User2">
	<!-- 将插入记录的主键返回
		order="BEFORE":在执行insert之前执行select uuid()这条SQL语句,得到主键值
		resultType:select uuid()结果的类型
		keyProperty:实体类对应的属性名
	-->
	<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
		select uuid()
	</selectKey>
	insert into t_user values(#{id}, #{username}, #{age})
</insert>
  • 编写测试代码
    在这里插入图片描述
    在这里插入图片描述

删除用户

  • 映射配置文件
    在这里插入图片描述

  • 程序代码
    在这里插入图片描述

更新用户

  • 映射配置文件
    在这里插入图片描述
  • 程序代码
    在这里插入图片描述

总结

  • parameterType:在映射配置文件中指定输入参数类型:基本类型或引用类型:该属性可以省略,例如没有参数

  • resultType:在映射配置文件中指定输出结果的类型:该属性可以省略

  • #{}:表示一个占位符,#{}接收输入参数,类型可以是基本类型、pojo、hashmap
    (1) 类型如果是基本类型:#{}可以写成value或其他值:建议一律写成value
    (2) 类型如果是pojo类型:通过OGNL读取对象中属性值,通过属性.属性.属性…方式获取对象属性值

  • ${}:表示一个拼接符号,会引入SQL注入,所以不建议使用(可以使用#{}占位符,在Java代码给出模式匹配的语句)!
    在这里插入图片描述
    ${value}表示接收输入参数的内容,其类型可以是基本类型、pojo、hanshmap:
    (1) 类型如果是基本类型: ${value}中只能写 value,即只能是${value}
    (2) 类型如果是pojo类型:通过OGNL读取对象中属性值,通过属性.属性.属性…方式获取对象属性值

  • SqlSession#selectOne():表示查询出一条记录进行映射:如果用selectOne可以实现的那么也可以使用selectList来实现:list中只有一个对象而已

  • SqlSession#selectList():表示查询出多条记录进行映射成一个列表:如果使用selectList查询多条记录则不能使用selectOne来替代:否则会抛出异常


MyBatis与Hibernate本质区别与应用场景

  • Hibernate是一个标准的ORM框架:对象关系映射框架:入门门槛较高、不需要编写SQL语句,SQL语句就自动生成了:但是对SQL语句进行优化、修改比较困难
  • Hibernate应用场景:适用于需求变化不多的中小型项目,比如:后台管理系统、ERP、CRM、OA
  • MyBatis专注于SQL本身,需要程序猿自己编写SQL语句:SQL优化、修改比较方便
  • MyBatis是一个不完全的ORM框架:虽然程序猿需要自己写SQL,MyBatis也可以实现映射:输入映射与输出映射
  • MyBatis应用场景:适用于需求变化较多的项目,比如:互联网项目
  • 企业进行技术选型:以低成本、高回报作为技术选型的原则,根据项目组的技术力量进行选择

SqlSession使用范围

SqlSessionFactoryBuilder

  • 通过SqlSessionFactoryBuilder来创建会话工厂SqlSessionFactory
  • 将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder
  • 在需要创建SqlSessionFactory对象时,只需要new一个SqlSessionFactoryBuilder即可

SqlSessionFactory

  • 通过SqlSessionFactory创建SqlSession,使用单例模式管理SqlSessionFactory:工厂一旦创建就使用有一个实例
  • 将来MyBatis和Spring整合后,使用单例模式管理SqlSessionFactory
  • SqlSessionFactory是单例模式,SqlSessionFactory是由SqlSessionFactoryBuilder创建的,那么也要求SqlSessionFactoryBuilder是单例模式吗?不要求:将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理:在需要创建SqlSessionFactory对象时,只需要new一个SqlSessionFactoryBuilder即可:因为SqlSessionFactory已经是单例管理了,那么SqlSessionFactoryBuilder只会new一次
package com.ycom.mybatis.util;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtils {
	private static final SqlSessionFactory sqlSessionFactory;
	
	static {
		String resource = "SqlMapConfig.xml";// 全局配置文件放在src目录下
		InputStream inputStream = null;
		try {
			inputStream = Resources.getResourceAsStream(resource);
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static SqlSessionFactory getSqlSessionFactory() {
		return sqlSessionFactory;
	}
}

SqlSession

  • SqlSession是面向用户(程序猿)的接口
  • SqlSession提供了很多用于操作数据库的方法:例如selectOne(返回单个对象)与selectList(返回单个或多个对象)
  • SqlSession是线程不安全的:SqlSession的实现类中除了接口中操作数据库的方法之外,还有数据域的属性,因为这些东西的存在就会导致线程不安全
    在这里插入图片描述
  • SqlSession中操作数据库的方法会修改数据域的属性值
  • SqlSession最佳的应用场合:方法体内:作为局部对象使用
  • 只要是线程不安全的对象都只能放在方法体内:局部对象是安全的

MyBatis的配置文件

  • MyBatis中的配置文件有两个:全局配置文件 与 映射配置文件:全局配置文件负责加载映射配置文件
  • 全局配置文件:全局配置文件的名称与位置没有固定要求:但是一般在开发中全局配置文件是直接放在src根目录下;全局配置文件的名称一般为:SqlMapConfig.xml
  • 映射配置文件:映射配置文件的名称与位置没有固定要求:但是根据不同的开发模式,映射配置文件的位置与名称有不同的约定规则:
    (1) 基于原生DAO开发模式:映射配置文件的名称一般为:实体类名称.xml,例如User.xml;映射配置文件的路径一般是在src目录下或src目录的子目录下
    (2) 基于Mapper代理开发模式:映射配置文件的名称一般为:实体类名称+Mapper.xml:例如UserMapper…xml;映射配置文件的路径与代理接口在同一目录下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值