MyBatis的认识及应用

# 一. MyBatis的认识

 

 

## 1.1 框架的认识

- 别人写的代码,解决了某一个方面的问题

## 1.2 MyBatis的认识

> 定义: 是一个ORM框架

- 用于和数据库打交道的框架,做数据库的增删改查

- MyBatis的底层依然是JDBC

- 帮我们消除了操作数据库的重复代码

- SQL是写在配置文件中

- ORM: 对象有关系映射

- O : 对象 -> JAVA是面向对象的语言

- R : 关系 -> Mysql是关系型数据库

- M : 映射


## 1.3 MyBatis的历史

- 原来叫做` ibatis`,后面改名叫做`mybatis`

## 1.4 框架的学习使用方式 【记住】

- 导包(核心包,依赖包)

- 写配置(xml或者properties)

- 启动框架 -> 找到核心类-> 找到配置文件


# 二. Hello-MyBatis

> 准备工作 : 数据库,表, domain , 项目结构
>

```java
package cn.itsource.domain;

public class Product {
private Long id;
//商品名称
private String productName;
//类别id
private Long dir_id;
//出售价格
private Double salePrice;
//供应商
private String supplier;
//品牌
private String brand;
//折扣
private Double cutoff;
//成本价
private Double costPrice;

// getter,setter与toString省略
}

```

 

## 2.1 导包

> 强调 : 以后只要是操作数据库的框架,底层都是JDBC,就一定要导入数据库驱动包

- 核心包 `mybatis-3.2.1.jar`
- 依赖包 `mybatis-3.2.1\lib\*.jar`
- 数据库驱动包 `mysql-connector-java-5.1.26-bin.jar`

## 2.2 核心配置文件 mybatis-config.xml

```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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--
配置数据源(连接池)的地方
mybatis自带连接池(性能会比原生的JDBC要好)
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///0831test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 去读取咱们的映射文件(写sql的xml文件) -->
<mappers>
<mapper resource="cn/itsource/domain/ProductMapper.xml"/>
</mappers>
</configuration>
```

 

## 2.3 映射配置文件 ProductMapper.xml

```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:映射(就是咱们的对象和数据库的映射)
xml必需要有个根,就是随便取个名称来做根而已
namespace:命名空间【可以随便乱写】,现在就把它当作是我们一个类的包名
规范命名: 全限定名+Mapper
-->
<mapper namespace="cn.itsource.domain.ProductMapper">
<!--
select:查询语句都写在这里面
id:唯一名称 咱们写Java代码需要找到这条sql,怎么找?
namespace+id : 可以唯一定位一条SQL
例:cn.itsource.domain.ProductMapper.findOne
parameterType:参数类型
这个long是大Long还是小long(_long)
resultType:返回的结果值(查询的其中一条数据的值)
注意:为了保证唯一性,这个类型必需中全限定名
-->
<select id="findOne" parameterType="long" resultType="cn.itsource.domain.Product">
select * from product where id = #{id}
</select>

</mapper>
```

 

## 2.4 代码实现与测试

### 2.4.1 代码实现 `ProductDaoImpl`

```java
/**
* 启动框架 关键点:搞到核心对象 -> SqlSession
* 有了 SqlSession,就可以做增删改查(CRUD)
* SqlSession -> 和SQL语句的一次对话
* SqlSessionFactory(工厂)Builder(建造者) -> SqlSessionFactory -> SqlSession
*/
@Override
public Product findOne(Long id) {

try {
//1.读取核心配置文件 mybatis-config.xml
/**
* MyBatis专门准备了一个类,提供了一个静态方法用来读取配置文件
*/
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//2.创建SqlSessionFactory -> 看作连接池
/**
* 通过建造者创建工厂
*/
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//3.获取SqlSession对象 -> 看作是一个连接
SqlSession session = factory.openSession();
//4.为所欲为(就可以操作数据库了)
/**
* 如果确定查询的数据只有一条,建议使用selectOne
* 第一个参数(statement): 查询SQL的字符串 -> 作用是定位到唯一的那条SQL
* 第二个参数:传参
*/
Product product = session.selectOne("cn.itsource.domain.ProductMapper.findOne",id);
return product;
} catch (Exception e) {
e.printStackTrace();
}

return null;
}
```

### 2.4.2 测试

> 以后在框架中出了错,从后面向前面找

```java

@Test
public void testFindOne() {
Product product = dao.findOne(1L);
System.out.println(product);

}
```

 

# 三. 工具类 MyBatisUtil

- 作用: 提供一个静态方法,可以直接提供SqlSession对象
- `SqlSessionFactoryBuilder` : 构造factory,用完即弃
- `SqlSessionFactory` : 只需要创建一次
- 是一个重量级对象,创建与销毁比较耗费资源和性能
- 有二级缓存, 连接池
- 它是线程安全的
- `SqlSession` : 操作数据库的对象

```java
package cn.itsource.util;

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

/**
* 这是一个关于MyBatis操作的工具类
* 1.单例 2.静态方法
* 主要:提供一个方法,可以直接获取到SqlSession对象
*
*/
public class MyBatisUtil {

//这个声明必需是静态的,静态代码块才可以引用
private static SqlSessionFactory factory = null;

/**
* 静态代码块:用到这个类就会执行,并且只会执行一次
* 我要在静态代码块中创建SqlSessionFactory对象
* 因为在实际开发中,这个对象只需要创建一个就可以了
*/
static{
try {
factory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsReader("mybatis-config.xml"));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 提供一个方法,可以直接获取到SqlSession对象
*/
public static SqlSession openSession(){
return factory.openSession();
}

}

```

 

# 四. CRUD

> 注意 : 增删改是需要提交事务

## 4.1 查询所有数据

- SQL

```xml
<!--
查询所有数据(不需要传参)
resultType:返回的是其中一条数据的类型
-->
<select id="findAll" resultType="cn.itsource.domain.Product" >
select * from product
</select>
```

- Java实现

```java
@Override
public List<Product> findAll() {
try {
//1.读取配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//2.创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//3.创建SqlSession对象
SqlSession session = factory.openSession();
//4.查询到所有数据并且返回
return session.selectList("cn.itsource.domain.ProductMapper.findAll");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
```

 

## 4.2 添加功能

- sql

```xml
<!-- 添加一条数据 -->
<insert id="save" parameterType="cn.itsource.domain.Product">
insert into product (
productName,dir_id,salePrice,supplier,brand,cutoff,costPrice
) values (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
```

- java

```java
/**
* 所有的操作数据库的框架,事务都需要我们手动提交
* 注意:事务没有提交,是不会把数据放到数据库中的
*/
@Override
public void save(Product product) {
SqlSession session = null;
try{
//1.获取SqlSession对象
session = MyBatisUtil.openSession();
//2.使用session执行添加功能
session.insert("cn.itsource.domain.ProductMapper.save",product);
//3.提交事务
session.commit();
}catch (Exception e) {
//如果发生了错误,事务需要回滚
session.rollback();
e.printStackTrace();
}finally{
//关闭会话
session.close();
}
}
```

 

## 4.3 修改功能

- sql

```xml
<!-- 修改一条数据 -->
<update id="update" parameterType="cn.itsource.domain.Product">
update product set
productName=#{productName},dir_id=#{dir_id},salePrice=#{salePrice},supplier=#{supplier},
brand=#{brand},cutoff=#{cutoff},costPrice=#{costPrice}
where id=#{id}
</update>
```

 

- java

```java
@Override
public void update(Product product) {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
//修改功能
session.update("cn.itsource.domain.ProductMapper.update",product);
//提交事务
session.commit();
} catch (Exception e) {
session.rollback();
e.printStackTrace();
}finally{
session.close();
}

}
```

 

## 4.4 删除功能

- sql

```xml
<!-- 删除一条数据 -->
<delete id="delete" parameterType="long">
delete from product where id=#{id}
</delete>
```

- java

```java
@Override
public void delete(Long id) {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
session.delete("cn.itsource.domain.ProductMapper.delete",id);
session.commit();
} catch (Exception e) {
session.rollback();
e.printStackTrace();
}finally{
session.close();
}
}
```

# 五. 映射 Mapper

> 只需要写接口,不需要写实现

- namespace必需和接口的全限定名对应上
- sql的id和方法名对应上

## 5.1 结构

 

 

 

## 5.2 ProductMapper.xml

```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">
<!-- 这个namespace指向的是和它配套的接口 -->
<mapper namespace="cn.itsource.mapper.ProductMapper">


<!-- long是一个别名,实际指向的 java.lang.Long -->
<select id="findOne" parameterType="long" resultType="product">
select * from product where id=#{id}
</select>

<select id="findAll" resultType="Product">
select * from product
</select>

....

</mapper>
```

 

## 5.3 ProductMapper

```java
public interface ProductMapper {
void save(Product product);
void update(Product product);
void delete(Long id);
//@Select("select * from product where id=#{id}")
Product findOne(Long id);
List<Product> findAll();
}
```

 

 

 

## 5.4 获取Mapper的代码

```java
/**
* MyBatis有办法自动帮我们把实现完成
*/
@Test
public void testFindAll() {
//1.拿到SqlSession
SqlSession session = MyBatisUtil.openSession();
//2.通过SqlSession拿到mapper的实现
ProductMapper mapper = session.getMapper(ProductMapper.class);
//3.测试查询功能
mapper.findAll().forEach(p->System.out.println(p));
}
```

# 六. 细节

## 6.1 日志的认识

- 对咱们的操作做相应的记录
- 其实和`System.out.println() `差不多的效果, 但是强大很多
- mybatis 使用日志功能来实现sql的显示

### 6.1.1 创建文件 `log4j.properties`

- 必需放在资源文件根目录
- 必需叫`log4j.properties`名称

### 6.1.2 代码(直接拷备)


#日志器logger #輸出器appender #布局器layout
#1.控制台输出
#指定日志器的输出级别和日志器的名称
#log4j.rootLogger=info,myconsole
#指定输出器
#log4j.appender.myconsole=org.apache.log4j.ConsoleAppender
#指定布局器
#log4j.appender.myconsole.layout=org.apache.log4j.SimpleLayout

#2.文件输出.txt
#指定日志器的输出级别和日志器的名称
#log4j.rootLogger=error,myfile
#指定输出器
#log4j.appender.myfile=org.apache.log4j.FileAppender
#log4j.appender.myfile.File=E:\\log4j.txt
#指定布局器(普通布局表示文本输出)
#log4j.appender.myfile.layout=org.apache.log4j.SimpleLayout

#3.文件输出.html
#指定日志器的输出级别和日志器的名称
#log4j.rootLogger=error,myhtml
#指定输出器
#log4j.appender.myhtml=org.apache.log4j.FileAppender
#log4j.appender.myhtml.File=D:\\log4j.html
#指定布局器(网页布局)
#log4j.appender.myhtml.layout=org.apache.log4j.HTMLLayout


#4.控制台输出+文件输出.txt
#指定日志器的输出级别和日志器的名称
#log4j.rootLogger=error,con,file
#指定输出器
#log4j.appender.con=org.apache.log4j.ConsoleAppender
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=D\:\\log4j.txt
#指定布局器(网页布局)
#log4j.appender.con.layout=org.apache.log4j.SimpleLayout
#log4j.appender.file.layout=org.apache.log4j.SimpleLayout


#5.控制台输出+自定义布局
log4j.rootLogger=DEBUG,my
#指定输出器
log4j.appender.my=org.apache.log4j.ConsoleAppender
#指定布局器(自定义布局)
#指定布局为自定义布局
log4j.appender.my.layout=org.apache.log4j.PatternLayout
#指定在自定义布局的格式,%d -- 表示当前系统时间,%t -- 执行该业务的线程名称,%p -- 日记器的级别,-5 -- 5表示输出字符的个数,符号表示右对齐
#%c -- 表示指定业务所在的类的完全限定名(包名.类名),%m -- 输出额外信息,%n -- 表示换行
log4j.appender.my.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
#设置package(可以是自定义的包也可以是api的包)输出级别
log4j.logger.org.springframework=info
log4j.logger.cn.itsource=debug

```

 

## 6.2 别名

- 别名是不区别大小写的
- 别名写在 `mybatis-config.xml`中

```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>
...
<!-- 为咱们使用的类取别名
type(类型)Aliases(别名)
结论:别名不区分大小写
-->
<typeAliases>
<!-- 只能为一个类取别名 -->
<!-- <typeAlias type="cn.itsource.domain.Product" alias="product"/> -->
<!-- 为这个包下面的所有类取别名 ,别名就是类名 -->
<package name="cn.itsource.domain"/>
</typeAliases>
....
</configuration>
```

## 6.3 #与$的区别 -> 面试题

> 如非必要,建议都使用#

- #代表占位符,$代表拼接字符串

- $是有SQL注入的问题,不建议使用 `order by 会使用$`

- $只能拿对象中的属性,而#支持获取单个值

```xml
<!--
#与$的区别:
1.#与$都是用来取值的,但是#会强大一点
$只能拿到对象/Map中的属性
#可以拿到对象/Map中的属性,也可以拿单个值
2.#与$取值方式不一样
$是直接拼接字符串 (产生SQL注入)
#占位符操作(只有一些特殊的地方可以使用占位符)
结论:可以使用#都使用#(优先)
order by ${ }
-->
<select id="findBy" parameterType="map" resultType="product">
select * from product where id=#{id}
</select>
```

## 6.4 添加返回id值

```xml
<!-- 添加一条数据
useGeneratedKeys:用不用主键(用就是true)
keyColumn:在数据库,主键是哪一列
keyColumn="id":在数据库中,id是主键
keyProperty:在类中,主键是哪一个属性
keyColumn="id":在类中,id是主键

-->
<insert id="save" parameterType="product"
useGeneratedKeys="true" keyColumn="id" keyProperty="id"
>
insert into product (
productName,dir_id,salePrice,supplier,brand,cutoff,costPrice
) values (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
```

 

## 6.5 jdbc.properties

> 以后连接数据库的配置都要单独写出来

### jdbc.properties

```properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///0831test
username=root
password=123456
```

### mybatis-config.xml 引入

```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>
<!-- 引入properties文件 -->
<properties resource="jdbc.properties" />
...
</configuration>
```

 

## 6.6 JDBC,MyBatis,Hibernate

 

posted @   你的未来归你  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示