- 一、三层架构
- 二、搭建MyBatis环境
- 三、动态代理
- 四、动态SQL
- 五、表的关联关系
- 六、事务
- 七、缓存
- 八、什么是ORM
一、三层架构
1.什么是三层架构
在项目开发中,遵循的一种形式模式.分为三层.
1)界面层:用来接收客 户端的输入,调用业务逻辑层进行功能处理,返回结果给客户端.过去的servlet就是界面层的功能.
2)业务逻辑层:用来进行整个项目的业务逻辑处理,向上为界面层提供处理结果,向下问数据访问层要数据.
3)数据访问层:专门用来进行数据库的增删改查操作,向上为业务逻辑层提供数据.
各层之间的调用顺序是固定的,不允许跨层访问.
界面层<———->业务逻辑层<———>数据访问层
二、搭建MyBatis环境
1.创建MySql数据库
use ssm;
CREATE TABLE `student` (
`id` int(11) AUTO_INCREMENT primary key ,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into student(name,email,age) values('张三','zhangsan@126.com',22);
insert into student(name,email,age) values('李四','lisi@126.com',21);
insert into student(name,email,age) values('王五','wangwu@163.com',22);
insert into student(name,email,age) values('赵六','zhaoliun@qq.com',24);
select * from student;
2.创建工程
1.创建一个空 Project
2.创建一个quickstart meaven 的Modules
3.修改目录
4.修改pom.xml
1)添加依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--添加MyBatis框架的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--添加mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
</dependencies>
2)添加资源文件指定
<!--添加资源文件的指定-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
3.在idea中添加数据库的可视化
4.添加jdbc.properties属性文件(数据库的配置)
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=123456
5.添加SqlMapConfig.xml文件,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>
<!--读取属性文件(jdbc.properties)
属性:
resources:从resources目录下找指定名称的文件加载
url:使用绝对路径加载属性文件
D:\course\16.MyBatis\04_project\mybatisall\mybatis_001_student\src\main\resources\jdbc.properties
-->
<properties resource="jdbc.properties"></properties>
<!--配置数据库的环境变量(数据库连接配置)
default:使用下面的environment标签的id属性进行指定配置
-->
<environments default="development">
<!--开发时在公司使用的数据库配置
id:就是提供给environments的default属性使用
-->
<environment id="development">
<!--配置事务管理器
type:指定事务管理的方式
JDBC:事务的控制交给程序员处理
MANAGED:由容器(Spring)来管理事务
-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源
type:指定不同的配置方式
JNDI:java命名目录接口,在服务器端进行数据库连接池的管理
POOLED:使用数据库连接池
UNPOLLED:不使用数据库连接池
-->
<dataSource type="POOLED">
<!--配置数据库连接的基本参数
private String driver;
private String url;
private String username;
private String password;
-->
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
<!--<!–在家的数据库配置–>-->
<!--<environment id="home">-->
<!--<transactionManager type=""></transactionManager>-->
<!--<dataSource type=""></dataSource>-->
<!--</environment>-->
<!--<!–上线后的数据库配置–>-->
<!--<environment id="online">-->
<!--<transactionManager type=""></transactionManager>-->
<!--<dataSource type=""></dataSource>-->
<!--</environment>-->
</environments>
<!--注册mapper.xml文件
resource:从resources目录下找指定名称的文件注册
url:使用绝对路径注册
class:动态代理方式下的注册
-->
<mappers>
<mapper resource=""></mapper>
</mappers>
</configuration>
添加:数据库连接池的基本概念
6.创建实体类Student,用来封装数据
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
//无参构造方法
//有参构造
//除了主键的有参构造
//set()和get()
//toString()
}
7.添加完成学生表的增删改查的功能的StudentMapper.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.xml文件中相同的id属性
-->
<mapper namespace="csy">
<!--
完成查询全部学生的功能
List<Student> getALL();
resultType:指定查询返回的结果集的类型,如果是集合,则必须是泛型的类型
parameterType:如果有参数,则通过它来指定参数的类型
-->
<select id="getAll" resultType="com.bjpowernode.pojo.Student" >
select id,name,email,age
from student
</select>
</mapper>
在SqlMapConfig.xml中注册mapper.xml文件
<!--注册mapper.xml文件
resource:从resources目录下找指定名称的文件注册
url:使用绝对路径注册
class:动态代理方式下的注册
-->
<mappers>
<mapper resource="StudentMapper.xml"></mapper>
</mappers>
8.创建测试类,进行功能测试
public class MyTest {
@Test
public void testA() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//取出sqlSession的对象
SqlSession sqlSession = factory.openSession();
//完成查询操作
List<Student> list =sqlSession.selectList("csy.getALl");
list.forEach(student -> System.out.println(student));
//关闭sqlSession
sqlSession.close();
}
}
9.完成增删改查
按主键查询学生
<!--
按主键id查询学生信息
Student getById(Integer id);
-->
<select id="getById" parameterType="int" resultType="com.bjpowernode.pojo.Student">
select id,name,email,age
from student
where id=#{id}
</select>
@Test
public void testGetById() throws IOException {
//读取核心配置文件
InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//取出SqlSession
SqlSession sqlSession = factory.openSession();
//按主键查学生
Student stu =sqlSession.selectOne("csy.getById",1);
System.out.println(stu);
//关闭SqlSession'
sqlSession.close();
}
完成模糊查询
<!--
按学生模糊查询
List<Student> getByName();
-->
<select id="getByName" parameterType="string" resultType="com.bjpowernode.pojo.Student">
select id,name,email,age
from student
where name like '%${name}%'
</select>
@Test
public void testGetByName() throws IOException {
//读取核心配置文件
InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//取出SqlSession
SqlSession sqlSession = factory.openSession();
//按主键查学生
List<Student> list =sqlSession.selectList("csy.getByName","张");
list.forEach(student -> System.out.println(student));
//关闭SqlSession'
sqlSession.close();
}
增加学生
<!--
增加学生
int insert(Student stu)
实体类:
private Integer id;
private String name;
private String email;
private Integer age;
-->
<insert id="insert" parameterType="com.bjpowernode.pojo.Student">
insert into student(name,email,age) values(#{name},#{email},#{age})
</insert>
@Test
public void testInsert() throws IOException {
//1.读取核心配置文件
InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.取出SqlSession
SqlSession sqlSession = factory.openSession();
//4.调用方法 //通过pojo实体类无主键有参构造方法传进去
int num=sqlSession.insert("csy.insert",new Student("haha","haha126@qq.com",23));
//切记切记:在所有的增删改查后必须手动提交事务
sqlSession.commit();
sqlSession.close();
}
删除学生
<!--
按主键删除学生
int delete (Integet id);
-->
<delete id="delete" parameterType="int">
delete from student where id=#{id}
</delete>
@Test
public void testDelete() throws IOException {
//1.读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.取出SqlSession
SqlSession sqlSession = factory.openSession();
//4.调用方法
int num = sqlSession.delete("csy.delete", 1);
System.out.println(num);
//切记切记:在所有的增删改查后必须手动提交事务
sqlSession.commit();
sqlSession.close();
}
更新学生
<!--
更新学生
int update(Student stu)
-->
<update id="update" parameterType="com.bjpowernode.pojo.Student">
update student set name=#{name},email=#{email},age=#{age}
where id=#{id}
</update>
@Test
public void testUpdate() throws IOException {
//1.读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.取出SqlSession
SqlSession sqlSession = factory.openSession();
//4.调用方法
int num=sqlSession.update("csy.update",new Student(3,"hehe","hehe@126.com",30));
System.out.println(num);
sqlSession.commit();
sqlSession.close();
}
10. SqlMapConfig.xml文件的优化
优化测试类
public class MyTest {
SqlSession sqlSession;
@Before //在所有的@Test方法执行前先执行的代码
public void openSqlSession() throws IOException {
//1.读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.取出SqlSession
sqlSession = factory.openSession();
}
@After
public void closeSqlSession(){
//关闭sqlSession
sqlSession.close();
}
@Test
public void testInsert() throws IOException {
int num = sqlSession.insert("csy.insert", new Student("haha", "haha126@qq.com", 23));
//切记切记:在所有的增删改查后必须手动提交事务
sqlSession.commit();
}
}
实体类别名注册
单个实体类注册
<properties resource="jdbc.properties"></properties>
<!--设置日志输出底层执行代码-->
<!--注册实体类的别名-->
<typeAliases>
<!--单个实体类别名注册-->
<typeAlias type="com.bjpowernode.pojo.Student" alias="student"></typeAlias>
</typeAliases>
<environments default="development">
....
</environment>
<update id="update" parameterType="student">
update student set name=#{name},email=#{email},age=#{age}
where id=#{id}
</update>
批量注册别名
如果类名是studentone 则别名为 studentOne
<typeAliases>
<!--批量注册别名
别名是类名的驼峰命名法(规范)-->
<package name="com.bjpowernode.pojo"></package>
</typeAliases>
<update id="update" parameterType="student">
update student set name=#{name},email=#{email},age=#{age}
where id=#{id}
</update>
设置日志输出
<!--设置日志输出底层执行代码-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
三、动态代理
1.动态代理存在的意义
在三层架构中,业务逻辑层要通过接口访问数据访问层的功能.动态代理可以实现.
2.动态代理的七个规范
动态代理的实现规范:
1)UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下.
2)UsersMapper.xml文件与UsersMapper.java的接口的文件名必须一致,后缀不管.
3)UserMapper.xml文件中标签的id值与与UserMapper.java的接口中方法的名称完全一致.
4)UserMapper.xml文件中标签的parameterType属性值与与UserMapper.java的接口中方法的参数类型完全一致.
5)UserMapper.xml文件中标签的resultType值与与UserMapper.java的接口中方法的返回值类型完全一致.
6)UserMapper.xml文件中namespace属性必须是接口的完全限定名称com.bjpowernode.mapper.UsersMapper
7)在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称com.bjpowernode.mapper.UsersMapper.
3.动态代理的实现步骤
1.创建表
use ssm;
-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(2) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `users` VALUES (1, '王五', '2000-09-10', '2', '安徽');
INSERT INTO `users` VALUES (2, '张三', '2001-07-12', '1', '北京市');
INSERT INTO `users` VALUES (3, '张小明', '1999-02-22', '1', '河南');
INSERT INTO `users` VALUES (4, '陈小亮', '2002-11-19', '1', '辽宁');
INSERT INTO `users` VALUES (5, '张三丰', '2001-03-10', '1', '上海市');
INSERT INTO `users` VALUES (6, '陈小明', '2002-01-19', '1', '重庆市');
INSERT INTO `users` VALUES (7, '王五四', '2001-05-13', '2', '天津市');
select * from users;
2.创建工程
1)创建一个quickstart meaven 的Modules
2)修改目录
3)修改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>com.bjpowerndoe</groupId>
<artifactId>mybatis_02_student</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--添加MyBatis框架的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--添加mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
</dependencies>
<!--添加资源文件的指定-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
</project>
3.完成resources下面的文件
1)添加jdbc.properties属性文件(数据库的配置)
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=123456
2)添加SqlMapConfig.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 resource="jdbc.properties"></properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.bjpowerndoe.pojo"></package>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class=" "></mapper>
</mappers>
</configuration>
4.添加实体类
public class Users {
private Integer id;
private String userName;
private Date birthday;
private String sex;
private String address;
//无参构造
//有参构造
//有参构造不包括主键
//set()和get()
//toString()
}
5.完成mapper下面的文件
1.新建UsersMapper接口
public interface UsersMapper {
//查询全部用户信息
List<Users> getAll();
}
2.新建UsersMapper.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="com.bjpowernode.mapper.UsersMapper">
<!--
//查询全部用户信息
List<Users> getAll();
-->
<select id="getAll" resultType="users">
select id,username,birthday,sex,address
from users;
</select>
</mapper>
6.添加测试类,测试功能
public class MyTest {
SqlSession sqlSession;
@Before
public void openSqlSession() throws IOException {
//1.读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建工厂对象
SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);
//3.取出sqlSession
sqlSession=factory.openSession();
}
@After
public void closeSqlSession(){
sqlSession.close();
}
@Test
public void testGetAll(){
//取出动态代理的对象,完成接口中方法的调用,实则是调用xml文件中相应的标签的功能。
UsersMapper uMapper =sqlSession.getMapper(UsersMapper.class);
System.out.println(uMapper.getClass());
//就是在调用接口的方法,mybatis框架已经为我们把功能代理出来了
List<Users> list = uMapper.getAll();
list.forEach(users -> System.out.println(users));
}
}
7.完成增删改查
用户的更新
//用户的更新
int update(Users users);
<!--
//用户的更新
int update(Users users);
private Integer id;
private String userName;
private Date birthday;
private String sex;
private String address;
-->
<update id="update" parameterType="users">
update users set username=#{userName},birthday=#{birthday},sex=#{sex},address=#{address}
where id=#{id}
</update>
public class MyTest {
SqlSession sqlSession;
UsersMapper uMapper;
//日期格式化刷子
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
@Before
public void openSqlSession() throws IOException {
//1.读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建工厂对象
SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);
//3.取出sqlSession
sqlSession=factory.openSession();
//取出动态代理的对象,完成接口中方法的调用,实则是调用xml文件中相应的标签的功能。
uMapper =sqlSession.getMapper(UsersMapper.class);
}
@After
public void closeSqlSession(){
sqlSession.close();
}
@Test
public void testUpdate() throws ParseException {
Users u = new Users(7,"haha",sf.parse("2000-01-01"),"2","下海");
int num=uMapper.update(u);
//切记切记切记:手工提交事务
sqlSession.commit();
}
}
根据主键查询
//根据用户主键查询用户
Users getById(Integer id);
<!--
//根据用户主键查询用户
Users getById(Integer id);
-->
<select id="getById" parameterType="int" resultType="users">
select id,username,birthday,sex,address
from users where id=#{id};
</select>
/*SqlSession sqlSession;
UsersMapper uMapper;
在update中被封装了
*/
@Test
public void testById(){
Users u =uMapper.getById(1);
System.out.println(u);
}
模糊查询
//模糊查询
List<Users> getByName(String name);
<!-- //模糊查询
List<Users> getByName(String name); -->
<select id="getByName" parameterType="string" resultType="users">
select id,username,birthday,sex,address
from users
where username like '%${name}%'
</select>
@Test
public void testGetByName(){
List<Users> list =uMapper.getByName("小");
list.forEach(users -> System.out.println(users));
}
增加用户
//增加用户
int insert(Users users);
<!--
//增加用户
int insert(Users users);
-->
<insert id="insert" parameterType="users">
insert into users (username,birthday,sex,address) values
(#{userName},#{birthday},#{sex},#{address})
</insert>
public void testinsert() throws ParseException {
Users u = new Users("hehe",sf.parse("2001-01-01"),"2","大兴");
int num=uMapper.insert(u);
System.out.println(num);
sqlSession.commit();
}
根据id删除用户
//根据主键删除用户
int delete(Integer id);
<!--
//根据主键删除用户
int delete(Integer id);
-->
<delete id="delete" parameterType="int">
delete from users
where id=#{id}
</delete>
@Test
public void testDelete() {
int num=uMapper.delete(1);
System.out.println(num);
sqlSession.commit();
}
8.完成mapper.xml文件的优化
<mappers>
<!--注册mapper.xml文件
<mapper class="com.bjpowernode.mapper.UsersMapper"></mapper>
-->
<!--批量注册-->
<package name="com.bjpowernode.mapper"></package>
</mappers>
4.#{}和${}
#{}占位符
传参大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问 ,防止sql注入.
#{}里如何写,看parameterType参数的类型
1)如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里随便写.
<select id="getById" parameterType="int" resultType="users"> ===>入参类型是简单类型
select id,username,birthday,sex,address
from users
where id=#{zar} ===>随便写
</select>
2)parameterType的类型是实体类的类型,则#{}里只能是类中成员变量的名称,而且区分大小写.
<insert id="insert" parameterType="users" > ===>入参是实体类
insert into users (username, birthday, sex, address) values(#{userName},#{birthday},#{sex},#{address}) ==>成员变量名称
</insert>
${}字符串拼接或字符串替换
1)字符串拼接,一般用于模糊查询中.建议少用,因为有sql注入的风险.
也分两种情况,同样的看parameterType的类型
A. 如果parameterType的类型是简单类型,则${}里随便写,但是分版本,如果是3.5.1及以下的版本,只以写value.
<select id="getByName" parameterType="string" resultType="users"> ===>入参是简单类型
select id,username,birthday,sex,address
from users
where username like '%${zar}%' ===>随便写
</select>
B. 如果parameterType的类型是实体类的类型,则${}里只能是类中成员变量的名称.(现在已经少用)
(1)优化模糊查询
C. 优化后的模糊查询(以后都要使用这种方式)
<select id="getByNameGood" parameterType="string" resultType="users">
select id,username,birthday,sex,address
from users
where username like concat('%',#{name},'%')
</select>
2)字符串替换
需求:模糊地址或用户名查询
select from users where username like ‘%小%’;
select from users where address like ‘%市%’
<!--
//模糊用户名和地址查询
//如果参数超过一个,则parameterType不写
List<Users> getByNameOrAddress(
@Param("columnName") ===>为了在sql语句中使用的名称
String columnName,
@Param("columnValue") ===>为了在sql语句中使用的名称
String columnValue);
-->
<select id="getByNameOrAddress" resultType="users">
select id,username,birthday,sex,address
from users
where ${columnName} like concat('%',#{columnValue},'%') ==>此处使用的是@Param注解里的名称
</select>
@Test
public void testGetByNameOrAddress(){
List<Users> list =uMapper.getByNameOrAddress("address","市");
list.forEach(users -> System.out.println(users));
}
3)返回主键值
在插入语句结束后, 返回自增的主键值到入参的users对象的id属性中.
<insert id="insert" parameterType="users" >
<selectKey keyProperty="id" resultType="int" order="AFTER">
select last_insert_id()
</selectKey>
insert into users (username, birthday, sex, address) values(#{userName},#{birthday},#{sex},#{address})
</insert>
keyProperty: users对象的哪个属性来接返回的主键值
resultType:返回的主键的类型
order:在插入语句执行前,还是执行后返回主键的值
UUID(补充)
这是一个全球唯一随机字符串,由36个字母数字中划线组.
UUID uuid = UUID.randomUUID();
System.out.println(uuid.toString().replace(“-“,””).substring(20));
四、动态SQL
1.什么是动态sql
可以定义代码片断,可以进行逻辑判断,可以进行循环处理(批量处理),使条件判断更为简单.
下面举的例子中:相当于省略了1=1
select * from users
where 1=1
and sex=1
and username='%小%'
sql
1)
2)
<!--定义代码片断-->
<sql id="allColumns">
id,username,birthday,sex,address
</sql>
//引用定义好的代码片断
<select id="getAll" resultType="users" >
select <include refid="allColumns"></include>
from users
</select>
if和where
test条件判断的取值可以是实体类的成员变量,可以是map的key,可以是@Param注解的名称.
<select id="getByCondition" parameterType="users" resultType="users">
select <include refid="allColumns"></include>
from users
<where>
<if test="userName != null and userName != ''">
and username like concat('%',#{userName},'%')
</if>
<if test="birthday != null">
and birthday = #{birthday}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
<if test="address != null and address != ''">
and address like concat('%',#{address},'%')
</if>
</where>
</select>
@Test
public void testGetByCondition()throws Exception{
Users u = new Users();
//如果不赋值,则是查找所有
u.setUserName("小");
u.setSex("1");
u.setAddress("市");
u.setBirthday(sf.parse("2002-01-19"));
List<Users> list = usersMapper.getByCondition(u);
list.forEach(users -> System.out.println(users));
}
set
<update id="updateBySet" parameterType="users">
update users
<set>
<if test="userName != null and userName != ''">
username = #{userName},
</if>
<if test="birthday != null">
birthday = #{birthday},
</if>
<if test="sex != null and sex != ''">
sex = #{sex},
</if>
<if test="address != null and address != ''">
address =#{address} ,
</if>
</set>
where id = #{id}
</update>
Test
public void testUpdateSet()throws Exception{
// Users u = new Users("哈哈",new Date(),"1","北京亦庄大兴");
//Users u = new Users(3,"不知道",sf.parse("1998-08-08"),"2","北京亦庄大兴888");
Users u = new Users();
u.setId(2);
u.setUserName("认识张三不");
//u.setSex("2");
//u.setBirthday(sf.parse("2000-01-01"));
int num = usersMapper.updateBySet(u);
//切记切记:必须提交事务
sqlSession.commit();
System.out.println(num);
}
foreach
<select id="getByIds" resultType="users">
select <include refid="allColumns"></include>
from users
where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
collection:用来指定入参的类型,如果是List集合,则为list,如果是Map集合,则为map,如果是数组,则为array.
item:每次循环遍历出来的值或对象
separator:多个值或对象或语句之间的分隔符
open:整个循环外面的前括号
close:整个循环外面的后括号
<delete id="deleteBatch" >
delete from users
where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<insert id="insertBatch">
insert into users(username, birthday, sex, address) values
<foreach collection="list" item="u" separator="," >
(#{u.userName},#{u.birthday},#{u.sex},#{u.address})
</foreach>
</insert>
指定参数位置
如果入参是多个,可以通过指定参数位置进行传参. 是实体包含不住的条件.实体类只能封装住成员变量的条件.如果某个成员变量要有区间范围内的判断,或者有两个值进行处理,则实体类包不住.
例如:查询指定日期范围内的用户信息.
<select id="getByBirthday" resultType="users">
select <include refid="allColumns"></include>
from users
where birthday between #{arg0} and #{arg1}
</select>
入参是map(重点掌握)
如果入参超过一个以上,使用map封装查询条件,更有语义,查询条件更明确.
<!--
//入参是map
List<Users> getByMap(Map map);
#{birthdayBegin}:就是map中的key
-->
<select id="getByMap" resultType="users" >
select <include refid="allColumns"></include>
from users
where birthday between #{birthdayBegin} and #{birthdayEnd}
</select>
测试类中
@Test
public void testGetByMap() throws ParseException {
Date begin = sf.parse("1999-01-01");
Date end = sf.parse("1999-12-31");
Map map = new HashMap<>();
map.put("birthdayBegin",begin);
map.put("birthdayEnd", end);
List<Users> list = uMapper.getByMap(map);
list.forEach(users -> System.out.println(users));
}
返回值是map
如果返回的数据实体类无法包含,可以使用map返回多张表中的若干数据.返回后这些数据之间没有任何关系.就是Object类型.返回的map的key就是列名或别名.
<!--
//返回值是map(一行)
Map getReturnMap(Integer id);
-->
<select id="getReturnMap" parameterType="int" resultType="map">
select username name,address add <!--name是username的别名,add是address的别名-->
from users
where id=#{id}
</select>
<!--
//返回多行的map
List<Map> getMulMap();
-->
<select id="getMulMap" resultType="map">
select username,address
from users
</select>
测试类
@Test
public void testGetReturnMapOne(){
Map<String,Object> map = mapper.getReturnMapOne(7);
System.out.println(map);
System.out.println(map.get("name"));
}
@Test
public void testGetReturnMap(){
List<Map<String,Object>> list = mapper.getReturnMap();
list.forEach(map-> System.out.println(map));
}
使用别名进行成员变量和列明的映射
实体类中: id,name
数据库中:bookid,bookname
<mapper namespace="com.bjpowernode.mapper.BookMapper">
<!--
查询全部图书
List<Book> getAll();
-->
<!--使用resultMap手工完成映射--> <!--这个book是泛型中的类型-->
<resultMap id="bookmap" type="book">
<!--主键绑定-->
<id property = "id" column="bookid"></id>
<!--非主键绑定-->
<result property="name" column="bookname"></result>
</resultMap>
<select id="getAll" resultMap="bookmap">
select bookid,bookname
from book
</select>
</mapper>
五、表的关联关系
一对多关联关系
客户和订单就是典型的一对多关联关系.
一个客户名下可以有多个订单.
客户表是一方,订单表是多方.客户一中持有订单的集合.
使用一对多的关联关系,可以满足查询客户的同时查询该客户名下的所有订单.
<mapper namespace="com.bjpowernode.mapper.CustomerMapper">
<!--
//根据客户的id查询客户所有信息并同时查询该客户名下的所有订单
Customer getById(Integer id)
实体类:
//customer表中的三个列
private Integer id;
private String name;
private Integer age;
//该客户名下的所有订单的集合
private List<Orders> ordersList;
-->
<resultMap id="customermap" type="customer">
<!--主键绑定-->
<id property="id" column="cid"></id>
<!--非主键绑定-->
<result property="name" column="name"></result>
<result property="age" column="age"></result>
<!--多出来的一咕噜绑定ordersList
Orders实体类:
private Integer id;
private String orderNumber;
private Double orderPrice;
-->
<collection property="ordersList" ofType="orders">
<!--主键绑定-->
<id property="id" column="oid"></id>
<!--非主键绑定-->
<result property="orderNumber" column="orderNumber"></result>
<result property="orderPrice" column="orderPrice"></result>
</collection>
</resultMap>
<select id="getById" parameterType="int" resultMap="customermap">
select c.id cid,name,age,o.id oid,orderNumber,orderPrice,customer_id
from customer c left join orders o on c.id = o.customer_id
where c.id=#{id}
</select>
</mapper>
多对一关联关系.
订单和客户就是多对一关联.
站在订单的方向查询订单的同时将客户信息查出.
订单是多方,会持有一方的对象.客户是一方.
<mapper namespace="com.bjpowernode.mapper.OrdersMapper">
<!--
//根据主键查询订单,并同时查询下此订单的客户信息
Orders getById(Integer id);
-->
<!--
手工绑定数据
实体类
private Integer id;
private String orderNumber;
private Double orderPrice;
//关联下此订单的客户信息,多方持有一方的对象
private Customer customer;
-->
<resultMap id="ordersmap" type="orders">
<!--主键绑定-->
<id property="id" column="oid"></id>
<!--非主键绑定-->
<result property="orderNumber" column="orderNumber"></result>
<result property="orderPrice" column="orderPrice"></result>
<!--多出来的一咕噜绑定
private Integer id;
private String name;
private Integer age;
//该客户名下的所有订单的集合,一方持有多方的集合
private List<Orders> ordersList; //不用管
-->
<association property="customer" javaType="customer">
<id property="id" column="cid"></id>
<result property="name" column="name"></result>
<result property="age" column="age"></result>
</association>
</resultMap>
<select id="getById" parameterType="int" resultMap="ordersmap">
select o.id oid,orderNumber,orderPrice,customer_id,c.id cid,name,age
from orders o inner join customer c on o.customer_id = c.id
where o.id=#{id}
</select>
</mapper>
24.一对一关联
25.多对多关联
总结:无论是什么关联关系,如果某方持有另一方的集合,则使用
六、事务
多个操作同时完成,或同时失败称为事务处理.
事务有四个特性:一致性,持久性,原子性,隔离性.
下订单的业务:
1)订单表中完成增加一条记录的操作
2)订单明细表中完成N条记录的增加
3)商品数据更新(减少)
4)购物车中已支付商品删除
5)用户积分更新(增加)
在MyBatis框架中设置事务
可设置为自动提交
sqlSession = factory.openSession(); ===>默认是手工提交事务,设置为false也是手工提交事务,如果设置为true,则为自动提交.
sqlSession = factory.openSession(true); ===>设置为自动提交,在增删改后不需要commit();
七、缓存
MyBatis框架提供两级缓存,一级缓存和二级缓存.默认开启一级缓存.
缓存就是为了提高查询效率.
使用缓存后,查询的流程:
查询时先到缓存里查,如果没有则查询数据库,放缓存一份,再返回客户端.下次再查询的时候直接从缓存返回,不再访问数据库.如果数据库中发生commit()操作,则清空缓存.
一级缓存使用的是SqlSession的作用域,同一个sqlSession共享一级缓存的数据.
二级缓存使用的是mapper的作用域,不同的sqlSession只要访问的同一个mapper.xml文件,则共享二级缓存作用域.
八、什么是ORM
ORM(Object Relational Mapping):对象关系映射
MyBatis框架是ORM非常优秀的框架.
java语言中以对象的方式操作数据,存到数据库中是以表的方式进行存储,对象中的成员变量与表中的列之间的数据互换称为映射.整个这套操作就是ORM.
持久化的操作:将对象保存到关系型数据库中 ,将关系型数据库中的数据读取出来以对象的形式封装
MyBatis是持久化层优秀的框架.
添加:resultType:指定查询返回的结果集的类型,如果是集合,则必须是泛型的类型
<select id="getAll" resultType="com.bjpowernode.pojo.Student" >
select id,name,email,age
from student
</select>
public class Users implements java.io.Serializable {
private Long id;
private String name;
private String password;
private String telephone;
private String username;
private String isadmin;
private Set houses = new HashSet(0);
set()….get()……
}
create table USERS
(
ID NUMBER(10) primary key,
NAME VARCHAR2(50),
PASSWORD VARCHAR2(50),
TELEPHONE VARCHAR2(15),
USERNAME VARCHAR2(50),
ISADMIN VARCHAR2(5)
);
<collection property="orders" ofType="order">
<id property="id" column="oid"></id>
<result property="orderNumber" column="ordernumber"></result>
<result property="orderPrice" column="orderprice"></result>
</collection>