- 一、三层架构
- 二、搭建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.Driverjdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=truejdbc.username=rootjdbc.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,agefrom student</select></mapper>
在SqlMapConfig.xml中注册mapper.xml文件
<!--注册mapper.xml文件resource:从resources目录下找指定名称的文件注册url:使用绝对路径注册class:动态代理方式下的注册--><mappers><mapper resource="StudentMapper.xml"></mapper></mappers>
8.创建测试类,进行功能测试
public class MyTest {@Testpublic void testA() throws IOException {//使用文件流读取核心配置文件SqlMapConfig.xmlInputStream 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));//关闭sqlSessionsqlSession.close();}}
9.完成增删改查
按主键查询学生
<!--按主键id查询学生信息Student getById(Integer id);--><select id="getById" parameterType="int" resultType="com.bjpowernode.pojo.Student">select id,name,email,agefrom studentwhere id=#{id}</select>
@Testpublic void testGetById() throws IOException {//读取核心配置文件InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//取出SqlSessionSqlSession 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,agefrom studentwhere name like '%${name}%'</select>
@Testpublic void testGetByName() throws IOException {//读取核心配置文件InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//取出SqlSessionSqlSession 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>
@Testpublic void testInsert() throws IOException {//1.读取核心配置文件InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//3.取出SqlSessionSqlSession 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>
@Testpublic void testDelete() throws IOException {//1.读取核心配置文件InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//3.取出SqlSessionSqlSession 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>
@Testpublic void testUpdate() throws IOException {//1.读取核心配置文件InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//3.取出SqlSessionSqlSession 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.取出SqlSessionsqlSession = factory.openSession();}@Afterpublic void closeSqlSession(){//关闭sqlSessionsqlSession.close();}@Testpublic 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.Driverjdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=truejdbc.username=rootjdbc.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,addressfrom users;</select></mapper>
6.添加测试类,测试功能
public class MyTest {SqlSession sqlSession;@Beforepublic void openSqlSession() throws IOException {//1.读取核心配置文件InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建工厂对象SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);//3.取出sqlSessionsqlSession=factory.openSession();}@Afterpublic void closeSqlSession(){sqlSession.close();}@Testpublic 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");@Beforepublic void openSqlSession() throws IOException {//1.读取核心配置文件InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建工厂对象SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);//3.取出sqlSessionsqlSession=factory.openSession();//取出动态代理的对象,完成接口中方法的调用,实则是调用xml文件中相应的标签的功能。uMapper =sqlSession.getMapper(UsersMapper.class);}@Afterpublic void closeSqlSession(){sqlSession.close();}@Testpublic 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,addressfrom users where id=#{id};</select>
/*SqlSession sqlSession;UsersMapper uMapper;在update中被封装了*/@Testpublic 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,addressfrom userswhere username like '%${name}%'</select>
@Testpublic 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 userswhere id=#{id}</delete>
@Testpublic 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,addressfrom userswhere 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,addressfrom userswhere username like '%${zar}%' ===>随便写</select>
B. 如果parameterType的类型是实体类的类型,则${}里只能是类中成员变量的名称.(现在已经少用)
(1)优化模糊查询
C. 优化后的模糊查询(以后都要使用这种方式)
<select id="getByNameGood" parameterType="string" resultType="users">select id,username,birthday,sex,addressfrom userswhere 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,addressfrom userswhere ${columnName} like concat('%',#{columnValue},'%') ==>此处使用的是@Param注解里的名称</select>
@Testpublic 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 userswhere 1=1and sex=1and 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>
@Testpublic 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>
Testpublic 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 userswhere 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 userswhere 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 userswhere birthday between #{arg0} and #{arg1}</select>
入参是map(重点掌握)
如果入参超过一个以上,使用map封装查询条件,更有语义,查询条件更明确.
<!--//入参是mapList<Users> getByMap(Map map);#{birthdayBegin}:就是map中的key--><select id="getByMap" resultType="users" >select <include refid="allColumns"></include>from userswhere birthday between #{birthdayBegin} and #{birthdayEnd}</select>
测试类中@Testpublic 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 userswhere id=#{id}</select><!--//返回多行的mapList<Map> getMulMap();--><select id="getMulMap" resultType="map">select username,addressfrom users</select>
测试类
@Testpublic void testGetReturnMapOne(){Map<String,Object> map = mapper.getReturnMapOne(7);System.out.println(map);System.out.println(map.get("name"));}
@Testpublic 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,booknamefrom 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><!--多出来的一咕噜绑定ordersListOrders实体类: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_idfrom customer c left join orders o on c.id = o.customer_idwhere 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,agefrom orders o inner join customer c on o.customer_id = c.idwhere 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,agefrom 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>
MyBatis框架结构

