MyBatis是一款持久层框架,用于简化JDBC开发。JavaEE三层架构:表现层[页面展示]、业务层[逻辑处理]、持久层[负责将数据保存到数据库]。
由于JDBC存在一些缺点:硬编码(例如,参数、SQL语句写入到代码中)、操作繁琐(手动设置参数和封装结果集),MyBatis就会设置配置文件、自动完成繁琐操作来解决上述问题。
1.创建user表tb_user
create database mybatis;
use mybatis;
drop table if exists tb_user;
create table tb_user(
id int primary key auto_increment,
username varchar(20),
password varchar(20),
gender char(1),
addr varchar(30)
);
INSERT INTO tb_user VALUES (1, 'zhangsan', '123', '男', '北京');
INSERT INTO tb_user VALUES (2, '李四', '234', '女', '天津');
INSERT INTO tb_user VALUES (3, '王五', '11', '男', '西安');
2.创建模块导入坐标,配置pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Mybatis-demo</groupId>
<artifactId>Mybatis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!--数据库连接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--添加日志slf4j的api-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!--添加logback-classic-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!--添加日志logback-core-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</project>
3.编写MyBatis核心配置文件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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 加载sql映射文件 -->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
4.编写SQL映射文件UserMapper.xml
(统一管理sql语句)
<?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="test">
<select id="selectAll" resultType="com.bhy.pojo.User">
select * from tb_user;
</select>
</mapper>
5.定义User类,连接数据库
package com.bhy;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author 神代言
* @version 1.0
*/
public class MybatisDemo {
public static void main(String[] args) throws IOException {
// 1.加载myatis的核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession对象,其执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.执行sql
List<Object> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
// 4.释放资源
sqlSession.close();
}
}
输入数据库名、用户名、密码,即可连接数据库。
连接成功如图所示,点击右侧笔的图标,即可在IDEA中编写SQL语句。
与1.1方式不同的是,设置了一个UserMapper接口
与UserMapper.xml
对应
**注意:**创建UserMapper.xml
的目录时一定要用com/bhy/mapper
,不能用com.bhy.mapper
!!!
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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 1.加载sql映射文件 -->
<!--<mapper resource="com\bhy\mapper\UserMapper.xml"/>-->
<!-- 2.Mapper代理方式 -->
<package name="com.bhy.mapper"/>
</mappers>
</configuration>
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">
<!--
namespace:名称空间, 代理方式保证命名空间namesapce与Mapper接口对应
-->
<mapper namespace="com.bhy.mapper.UserMapper">
<select id="selectAll" resultType="com.bhy.pojo.User">
select * from tb_user;
</select>
</mapper>
UserMapper.java
package com.bhy.mapper;
import com.bhy.pojo.User;
import java.util.List;
/**
* @author 神代言
* @version 1.0
*/
public interface UserMapper {
List<User> selectAll();
}
MybatisDemo2.java
package com.bhy;
import com.bhy.mapper.UserMapper;
import com.bhy.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author 神代言
* @version 1.0
*/
public class MybatisDemo2 {
public static void main(String[] args) throws IOException {
// 1.加载myatis的核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession对象,其执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
// // 传统方式仍存在硬编码问题
// List
// System.out.println(users);
// 3.执行sql(通过Mapper代理方式)
UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
List<User> users = usermapper.selectAll();
System.out.println(users);
// 4.释放资源
sqlSession.close();
}
}
该方式参考1.1和1.3
书写Mapper.xml
的注意事项:
一、数据库表的字段名称和实体类的属性名称不一样,则不能自动封装数据
解决方法:
(1)起别名:对不一样的列名起别名,让别名和实体类的属性名一样
缺点:每次查询都要定义一次别名,不灵活
(2)resultMap:定义标签,在标签中,使用resultMap属性替换 resultType属性
二、参数占位符:
三、动态条件查询
格式:< where>< if test=“条件判断”>and 查询语句< /if>< where>
if语句:(多条件动态查询)
select * from tb_brand
/* where 1 = 1*/
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
</if>
</where>
switch case语句:(单条件动态查询)
select * from tb_brand
<where>
<choose><!--相当于switch-->
<when test="status != null"> <!--相当于case-->
status = #{status}
</when>
<when test="companyName != null and companyName != '' "> <!--相当于case-->
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ''"> <!--相当于case-->
brand_name like #{brandName}
</when>
<otherwise> <!--相当于default-->
1 = 1
</otherwise>
</choose>
</where>
配置文件BrandMapper.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="com.bhy.mapper.BrandMapper">
<!--注意细节:
一、数据库表的字段名称 和 实体类的属性名称 不一样,则不能自动封装数据
* 起别名:对不一样的列名起别名,让别名和实体类的属性名一样
* 缺点:每次查询都要定义一次别名
* sql片段
* 缺点:不灵活
* resultMap:
1. 定义<resultMap>标签
2. 在<select>标签中,使用resultMap属性替换 resultType属性
-->
<!--
id:唯一标识
type:映射的类型,支持别名
-->
<resultMap id="brandResultMap" type="Brand">
<!--
id:完成主键字段的映射
column:表的列名
property:实体类的属性名
result:完成一般字段的映射
column:表的列名
property:实体类的属性名
-->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
select *
from tb_brand;
</select>
<!--
sql片段
-->
<!--
<sql id="brand_column">
id, brand_name as brandName, company_name as companyName, ordered, description, status
</sql>
<select id="selectAll" resultType="brand">
select
<include refid="brand_column" />
from tb_brand;
</select>
-->
<!--<select id="selectAll" resultType="brand">
select *
from tb_brand;
</select>-->
<!--
二、*参数占位符:
1. #{}:会将其替换为 ?,为了防止SQL注入
2. ${}:拼sql。会存在SQL注入问题
3. 使用时机:
* 参数传递的时候:#{}
* 表名或者列名不固定的情况下:${} 会存在SQL注入问题
* 参数类型:parameterType:可以省略
* 特殊字符处理:例如 < 号
1. 转义字符:
2. CDATA区:
-->
<!-- <select id="selectById" resultMap="brandResultMap">
select *
from tb_brand where id = #{id};
</select>
-->
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand
where id
<![CDATA[
<
]]>
#{id};
</select>
<!--
条件查询
-->
<!-- <select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where status = #{status}
and company_name like #{companyName}
and brand_name like #{brandName}
</select>-->
<!--
三、动态条件查询
格式:<where><if test="条件判断">and 查询语句</if><where>
* if: 条件判断
* test:逻辑表达式
* 问题:
* 恒等式
* <where> 替换 where 关键字
-->
<!-- 多条件动态查询 -->
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
/* where 1 = 1*/
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
</if>
</where>
</select>
<!--<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
where
<choose><!–相当于switch–>
<when test="status != null"><!–相当于case–>
status = #{status}
</when>
<when test="companyName != null and companyName != '' "><!–相当于case–>
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ''"><!–相当于case–>
brand_name like #{brandName}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
</select>-->
<!-- 单条件动态查询 -->
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
<where>
<choose><!--相当于switch-->
<when test="status != null"><!--相当于case-->
status = #{status}
</when>
<when test="companyName != null and companyName != '' "><!--相当于case-->
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ''"><!--相当于case-->
brand_name like #{brandName}
</when>
</choose>
</where>
</select>
<!-- 插入 -->
<!-- 返回主键:useGeneratedKeys="true" keyProperty="id" -->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
<!-- 动态更新 -->
<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName != ''">
brand_name = #{brandName},
</if>
<if test="companyName != null and companyName != ''">
company_name = #{companyName},
</if>
<if test="ordered != null">
ordered = #{ordered},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null">
status = #{status}
</if>
</set>
where id = #{id};
</update>
<delete id="deleteById">
delete from tb_brand where id = #{id};
</delete>
<!--
mybatis会将数组参数,封装为一个Map集合。
* 1.collection默认:array = 数组
* 2.使用@Param注解改变map集合的默认key的名称
separator="," open="(" close=")"可以解释为(,,,)
-->
<delete id="deleteByIds">
delete from tb_brand where id
in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
;
</delete>
</mapper>
映射接口文件BrandMapper.java
package com.bhy.mapper;
import com.bhy.pojo.Brand;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* @author 神代言
* @version 1.0
*/
public interface BrandMapper {
/**
* 查询所有
*/
List<Brand> selectAll();
/**
* 查看详情:根据Id查询
*/
Brand selectById(int id);
/**
* 条件查询
* * 参数接收
* 1. 散装参数:如果方法中有多个参数,需要使用@Param("SQL参数占位符名称")
* 2. 对象参数:对象的属性名称要和参数占位符名称一致
* 3. map集合参数
*
*/
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);
List<Brand> selectByCondition(Brand brand);
List<Brand> selectByCondition(Map map);
/**
* 单条件动态查询
* @param brand
* @return
*/
List<Brand> selectByConditionSingle(Brand brand);
/**
* 添加
*/
void add(Brand brand);
/**
* 修改
*/
int update(Brand brand);
/**
* 根据id删除
*/
void deleteById(int id);
/**
* 批量删除
*/
void deleteByIds(int[] ids);
}
测试文件MybatisBrandTest.java
package com.bhy;
import com.bhy.mapper.BrandMapper;
import com.bhy.pojo.Brand;
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.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MybatisBrandTest {
public static void main(String[] args) throws IOException {
}
@Test
public void testSQL() throws IOException {
// 1.加载myatis的核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession对象,其执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.执行sql(通过Mapper代理方式)
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 3.1 全部查询
List<Brand> brands = mapper.selectAll();
System.out.println(brands);
// 3.2 条件查询
Brand brand = mapper.selectById(2);
System.out.println(brand);
// (1) 散装参数
List<Brand> brands1 = mapper.selectByCondition(1, "%华为%", "%华为%");
System.out.println(brands1);
// (2)对象参数
Brand brand2 = new Brand();
brand2.setStatus(1);
brand2.setBrandName("%华为%");
brand2.setCompanyName("%华为%");
List<Brand> brands2 = mapper.selectByCondition(brand2);
System.out.println(brands2);
// (3) map集合参数
Map hashMap = new HashMap();
hashMap.put("status","1");
hashMap.put("brandName","%华为%");
hashMap.put("companyName","%华为%");
List<Brand> brands3 = mapper.selectByCondition(hashMap);
System.out.println(brands3);
// 3.3 动态查询
// 3.4 插入
brand2.setDescription("");
brand2.setOrdered(1);
mapper.add(brand2);
// 3.5 动态更新
brand2.setId(3);
brand2.setDescription("一般般");
mapper.update(brand2);
// 3.6 删除
int[] ids = {3,5,6};
mapper.deleteByIds(ids);
// 需要提交事务,才能把数据的增删改执行成功,不然会回滚
// 或者在定义sqlsession时设置为自动提交
// 例如:sqlSession = sqlSessionFactory.openSession(true);
sqlSession.commit();
// 4.释放资源
sqlSession.close();
}
}
将配置文件中的sql语句用注解方式写在接口BrandMapper.java
的方法上。