用简单表演示:
#创建数据库ssm
CREATE DATABASE ssm DEFAULT CHARSET utf8;
#使用(打开)ssm数据库
use ssm;
#创建表student
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);
学习时用的并非SpringBoot项目,所以安装使用SSM框架时的老配置
1.创建Maven项目
2.引入mysql驱动和Mybatis框架依赖
3.修改pom.xml添加资源文件指定
4.在idea中添加数据库的可视化(这个随自己)
5.添加jdbc.properties属性文件(数据库的配置)
6.添加SqlMapConfig.xml文件,该文件是Mybatis的核心配置文件
7.创建实体类用来封装数据
8.添加完成学生表的增删改查的功能StudentMapper.xml
9.测试
引入了单元测试,mysql驱动,mybatis框架
指定资源文件的原因,如果不指定,target文件会少东西,老的SSM配置是比较麻烦
自定资源文件后再运行单元测试(为了编译或者用maven编译下),看下target,
就是包含resources
idea支持数据库可视化
创建查询
在resources下引入jdbc.properties配置文件
其实注册mapper.xml文件也可以放到其地方,随你自己指定
建实体类
我这里命名空间乱写的
用单元测试看下配置对不对
Resources导入的是ibatis的,mybatis的前身就是ibatis
CRUD来一套
前面命名空间的意义在于分辨:比如两个接口 都有getAll()如何分辨就是namespace的意义
这里关于parameterType 类型映射表 其实可以不写,基本都省略不写了,左边是.XML的prameterType或者resultType的写法,对应右边java类型
也就是说如果参数是Map 那么parameterType或者resultType可以写成map
如果是自定义对象比如Student resultType需要具体包名+类名,比如com.hui.pojo.Student
现在很多时候用SpringBoot.我们写成resultType="Student",原因是配置文件配置了
mybatis或mybatis都可以这样配置
使用轮子
再来几遍
插入主键回传
新增时报错,原因mysql驱动版本太低,8.0那么jdbc驱动也需要改下
改变mysql驱动版本
jdbc driver改一下
再测试,OK
注意增删改需要commit
删除一个学生
更新
以上在单元测试中,创建SqlSession的代码都是重复的,关闭也是重复的
重温下在单元测试中的@Before和@After
在StudentMapper.xml中给单个实体类取别名,不然每次都要写parameterType="com.hrui.pojo.Student"
这样StudengMapper.xml里的parameterType和resultType可以简写成
parameterType="student" 和resultType="student"
测试也都OK
批量注册实体类别名
关于设置日志输出(sql语句参数类型等输出)
具体设置
执行时,在控制台输出
这里提一下动态代理
下面这个问题一时没有解决,先往下继续
下面重建个项目演示动态代理访问
新建张表用来演示
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;
上面表主键自增设置为27,意思就是主键从27开始
但是插入时候给了id,这样也是可以的,至少没有报错
引入需要的依赖
4.0.0 com.hrui mybatis-021.0-SNAPSHOT 8 8 junit junit4.12 test mysql mysql-connector-java8.0.29 org.mybatis mybatis3.5.6 org.projectlombok lombokRELEASE compile src/main/java ***.properties src/main/resources ***.properties
jdbc.properties.其实名字也随自己取
db.driver=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://xxxxxxxxxx:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true db.username=xxxxx db.password=xxxxxxx
关于SqlMapConfig.xml名字无所谓,随自己取名
主要作用
1.读取对应的jdbc.properties获得驱动,url,username,password等等或者初始化数据库连接池连接数,最大连接数等
22.设置日志输出
3.注册实体类别名
4.注册指定写sql的.xml位置等等
SqlMapConfig.xml
注意上面
idea配置数据库可视化
创建实体类
动态代理的实现规范:
1)UsersMapper.xml文件与UserMapper.java的接口必须同一个目录里(SpringBoot中另讲)
2)UsersMapper.xml文件与UserMapper.java的接口的文件名必须一致,后缀不管.(好像也有问题是吧哈哈)
3)UserMapper.xml文件中的标签的id值与UserMapper.java的接口中方法名一致
4)UserMapper.xml文件中的标签的parameterType属性值与UserMapper.java的接口中方法参数类型一致
5)UserMapper.xml文件中的标签的resultType值与UserMapper.java的接口中方法返回值类型一致
6)UserMapper.xml文件中namespace属性必须是接口的完全名(包名+类名)
7)在SqlMapConfig.xml文件中注册mapper文件时,使用
查看一个类的路径
测试
package com.hrui;
import com.hrui.mapper.UserMapper;
import com.hrui.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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyTest {
SqlSession sqlSession;
@Before
public void openSqlSession() throws IOException {
//使用文件流读取配置文件SqlMapConfig.xml
InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
//取出SqlSession对象
sqlSession=factory.openSession();
}
@After
public void closeSqlSession(){
//关闭
sqlSession.close();
}
@Test
public void testA(){
//取出动态代理对象,完成接口中方法的调用,实则是调用.xml文件中相同的标签的功能
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
System.out.println(userMapper.getClass());
List list=userMapper.getAll();
list.forEach(user-> System.out.println(user));
}
注意,我给.XML改个名字
但是我们在使用SpringBoot中好像没有这样.只要命名空间OK就行
糊弄下过去就是说肯定是某个属性改过了.了解后再说
练练手
.xml
select * from users
注意几点:
update一般传进来一个对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);代码重复,提取出来
这里birthday我是直接new Date()
SimpleDateFormat sdf=new SompleDateFormat("yyyy-MM-dd");
sdf.parse("1999-02-22");
具体代码
package com.hrui;
import com.hrui.mapper.UserMapper;
import com.hrui.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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class MyTest {
SqlSession sqlSession;
UserMapper userMapper;
//日期格式化
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
@Before
public void openSqlSession() throws IOException {
//使用文件流读取配置文件SqlMapConfig.xml
InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
//取出SqlSession对象
sqlSession=factory.openSession();
//取出动态代理对象,完成接口中方法的调用,实则是调用.xml文件中相同的标签的功能
userMapper=sqlSession.getMapper(UserMapper.class);
}
@After
public void closeSqlSession(){
//关闭
sqlSession.close();
}
@Test
public void testA(){
System.out.println(userMapper.getClass());
List list=userMapper.getAll();
list.forEach(user-> System.out.println(user));
}
@Test
public void testB(){
System.out.println(userMapper.getClass());
User user=userMapper.getUserById(1);
System.out.println(user);
}
@Test
public void testC(){
System.out.println(userMapper.getClass());
List users=userMapper.getUserByName("王");
users.forEach(user -> System.out.println(user));
}
@Test
public void testD() throws ParseException {
System.out.println(userMapper.getClass());
//int num = sqlSession.update("updateUser", new User(1, "小小王", new Date(), "1", "宁波"));
userMapper.updateUser(new User(1, "小小王", sdf.parse("2000-01-01"), "1", "宁波"));
sqlSession.commit();
}
@Test
public void testE(){
System.out.println(userMapper.getClass());
userMapper.saveUser(,new User("宝宝",new Date(),"2","杭州"));
sqlSession.commit();
}
@Test
public void testF(){
System.out.println(userMapper.getClass());
userMapper.deleteById(28);
sqlSession.commit();
}
}
比如前端传进来肯定是个字符串 "2000-01-01"或其他格式
上面比如可以这样
User user=new User(111,"haha",sdf.parse("2000-01-01"),"2","杭州");
用下面方式可以转化
但是很多框架都已经做好了
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") //返回时间类型 @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") //接收时间类型 @ApiModelProperty(value = "活动开始时间") private LocalDateTime startTime;
注意增删改还是需要sqlSession.commit()
#{}占位符底层使用的是PreparedStatement对象,是安全的数据库访问,防止sql注入
#{}里写什么,看parameterType参数类型
1)如果parameterType的类型是基本类型(8种基本(封装)类型+String)
且只有一个参数
则#{}里随便写
2)parameterType是实体类,则#{}里只能是类中成员变量,且#{userName}区分大小写
复杂的后面讲 甚至parameterType可以不写
${}字符串拼接或字符串替换
1)一般用于模糊查询中,其实我上面就没有用,有sql注入风险
如果用${}的话,模糊查询可以这样写
where username like '%${name}%',因为根本不提倡${}的写法,所以也没必要
同样
如果parameterType的类型是基本类型(8种基本(封装)类型+String)
且只有一个参数
则${}里随便写---->区分版本.如果是mybatis版本在3.5.1以下只能写${value}
2)如果是实体类,如上一样
${}用于字符串替换:比如如下
关于模糊查询:
比如 where username like concat('%',#{name},'%');就OK了
现在有个需求比如
select * form users where username like concat('%',#{userName},'%')
select * form users where address like concat('%',#{address},'%')
希望写一条sql搞定
需要用到列明只能用${}绝对不能用#{} 上面users写成user了 注意
但自己有次听课,记得mybatis某个版本后,多参数也不需要@Param注解了
关于主键回传:
业务需求比如:当插入一个用户后,我需要再另外一张表记录该插入用户的id
可是用户插入后我们不知道该用户id,难道我们再去查下用户表,看看刚插入的用户id是什么???完全没必要,mybatis有主键回传功能
就以前面写过的插入用户为例子
看下输出 id为null
现在我在.XML里加点东西
继续测试刚才的插入
id已经有了
另外sql里
select last_insert_id();可以看到查到最后一次或者说最近一次插入数据的id
主键回传的另外一种方式
select last_insert_id() insert into users(username,birthday,sex,address)values(#{userName},#{birthday},#{sex},#{address})
keyProperty:user对象的哪个属性来接返回的主键值
resultType:返回的主键的类型
order:在插入语句执行前,还是执行后返回主键的值(注意插入前根本不存在主键的值,还没插入呢)
关于UUID
关于动态SQL
select * from users 无条件查询
select * from users where sex=1 带一个条件查询
select * from users where sex=1 and username like '%市%' 带两个条件查询
比如上面三条sql,我们无法确定有几个条件
1)
2)
现学现用下面我们改造下sql
3)
4)
测试下
5)
比如更新35
这里如果你什么都不更新会报错
6)
collection:collection属性的值有三个,分别是list,array,map分别对应的参数类型为List,数组,map
item属性:循环体中具体的对象.支持属性点路径访问,如item.age,item.info.details,在list和数组中item指其中的对象,在map中item指value
index属性:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选.
open:表示该语句以什么开始
close:表示该语句以什么结束
separator:表示元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间","隔开,避免手动输入逗号导致sql错误,如in(1,2)这样.该参数可选
select * from users where id=2 or id=4 or id=6
或者select * from users where id in(2,4,6)
演示数组参数
.XML
也可以将两边括号写在foreach里面
测试
演示批量删除
数据库看下有没有删掉
演示批量插入
insert into user
(username,birthday,sex,address)
values
('a','1999-09-09','1','绍兴'),
('b','1999-09-09','1','绍兴2'),
('c','1999-09-09','1','绍兴3')
演示批量更新
报错
报错原因并非sql写错了什么的
而是需要设置使用批量更新操作
在jdbc.properties加&allowMultiQueries=true 允许多行操作
再次执行OK
关于parameterType 增删改查除了自定义实体类 都可以不写 简单类型想写就写,传入参数是集合数组都可以不写 ()
查询必须写resultType或者resultMap
标准做法就是parameterType除了8种基本类型包装类+String 或者实体类去写以下
其他都可以不写
甚至你就不写 能怎么地吧 哈哈哈哈
关于Mybatis指定参数下标位置查询(就是如果多参,不写@Param注解 如果指定下标查询)
这个问题记得mybatis改版后就不需要再写@Param注解区分参数,但是具体哪个版本忘记了
在mybatis版本3.4.1之前 直接between #{0} and #{1} 该版本之后 between #{arg0} and #{arg1}
可以用0,1,2,3,4,5,6,7等等下标来取值



