day01-mybatis笔记
今日内容:
mybatis框架的CRUD基本操作
一、框架(了解):
建筑学上:框架楼,只需要搭建骨架,里面的墙后期再去维护(工人)
软件开发上:骨架,由开源的组织研发的一个方便于程序员开发的一个骨架,程序员只需要在骨架之内进行维护操作,直接使用骨架(框架)
所学的框架的底层全部是反射机制
二、常用的框架
五种开源 框架:
mybatis(代替jdbc)
hibernate(代替jdbc,在企业开发中已经不用了)
spring(核心框架,贯穿其他优秀的框架)
springmvc(代替servlet)
struts2(代替servlet)
常用的框架组合:
ssm(spring+springmvc+mybatis)
主要应用的场景:互联网项目(互联网电商,互联网金融)
ssh(s2sh,ss2h)(spring+struts2+hibernate)
主要应用的场景:传统项目(学生管理系统,)目前来说政府项目
互联网项目和传统项目区分:
根据并发量来的,传统项目几乎没有并发量
三、三层架构(了解):
表现层
web阶段: servlet
框架阶段:springmvc
业务层
web阶段:service
框架阶段:spring
数据访问层
web阶段:dao
框架阶段:mybatis(持久层) mapper
四、mybatis概括(了解):
问题:
1.为什么学习mybatis
框架是已经编写好的,我们在开发过程中只需要使用这些框架
使用mybatis的好处:大大的减轻了程序员的工作负荷。
避免了jdbc几乎所有的手动编写的代码和获取结果集
ORM(对象关系映射): 分为ORM工具和ORM框架
ORM工具:springjdbcTemplate和dbutils
ORM框架:
mybatis(半自动框架) 需要写一部分sql
hibernate(全自动框架) 不需要写sql, hql
ORM思想:
其实就是javabean(实体类)关联映射数据库表,实体类其实就是数据库表字段的一个映射
实体类其实就是数据库表的虚构的一个类,运行在内存中,数据库表示在硬盘中
总结:持久层框架都是延续了ORM思想,换句话说使用框架,离不开实体类
2.怎么学习mybatis
3.mybatis是什么?
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。码云gitee oschina(开源中国)
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
掌握的信息:
第一。mybatis可以使用xml或者注解两种形式进行开发
第二。原生类型(int ,double,float,long,…),POJO(javaBean对象(domain))
第三。使用mybatis不在去写冗余的jdbc代码
4.怎么使用mybatis?
五、mybatis入门(掌握):
1.准备工作:
idea配置maven局部设置和全局设置
mybatis只需要对数据库进行CRUD操作,只需要创建jar工程
注意事项:
1.每一个框架中都会有一个自己的核心配置文件,mybatis的核心配置文件sqlMapConfig.xml
2.实体类映射文件xxMapper.xml(xxDao.xml)xx则表示实体类的名称
第一步,创建数据库表
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
第二步,导入依赖
<dependencies>
<!--mybatis的核心jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--日志依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
第二步,环境配置(xml版)
注意:mybatis的框架中有两个配置文件
在配置文件中第一行必须要加入该配置文件的约束
从使用mybatis之后,那么意味着dao只有接口没有实现类,用实体类映射文件来完成dao接口的实现
第一,编写domain
public class User implements Serializable{
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
第二,编写Dao
public interface IUserDao {
}
第三,核心配置文件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>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</configuration>
第四,实体类映射文件xxMapper.xml(xxDao.xml)
注意:目前来说实体类映射文件的名字要和dao接口的名称一致
<?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表示命名空间,属性值等于当前dao接口的全限名称
-->
<mapper namespace="com.itheima.dao.IUserDao">
</mapper>
2.入门查询操作
第一步,编写dao接口
//全查
public List<User> findAll();
第二步,编写IUserDao.xml
<!--全查
select标签表示查询标签,
id属性表示当前标签的名称,属性值等于当前dao接口中相对应方法的方法名称
相当于在dao实现类中去重写dao接口中的方法
resultType表示结果类型,
属性值
如果说返回值是List类型必须等于list集合中的泛型
如果说返回值是实体类类型的话,必须等于返回值
-->
<select id="findAll" resultType="com.itheima.domain.User">
SELECT * FROM user
</select>
第三步,注意,在sqlMapConfig.xml中必须加入关系映射
<!--核心配置文件去关联实体类映射文件-->
<mappers>
<mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
</mappers>
第四步,测试类
public static void main(String[] args) throws IOException {
//1.读取配置文件,生成字节输入流,目的是为了连接数据库
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//4.获取dao的代理对象(动态代理对象)
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
报错信息:
实体类映射文件没有被映射到(注册到)
解决方案:
在sqlMapConfig.xml中加入映射关联
报错2:
当前IUserDao.xml中出现了非法参数
3.新增操作
第一步,编写dao接口
//新增
public void insertUser(User user);
第二步,编写IUserDao.xml
<!--新增
mybatis中赋值的时候需要使用#{}形式
注意:#{参数},参数写什么取决当前接口的参数类型
如果说参数类型是实体类类型的话,那么#{参数}参数必须要和实体类中的相对应的属性名称一致
注意:新增,修改和删除,以及查询的时候如果说需要参数,可以不去在标签只能加上parameterType,如果不加,mybatis
会自动去当前对应的dao接口方法中去匹配类型,建议还是要加上该属性
parameterType参数类型,属性值目前来说必须是全限名称
-->
<insert id="insertUser" parameterType="com.itheima.domain.User">
INSERT INTO user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
第三步,测试类
private InputStream in;
private SqlSession sqlSession;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.获取SqlSession对象
sqlSession = factory.openSession();
//4.获取dao的代理对象
userDao = sqlSession.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//提交事务
sqlSession.commit();
//6.释放资源
sqlSession.close();
in.close();
}
/**
* 测试保存操作
*/
@Test
public void insertUser(){
User user = new User();
user.setUsername("二狗子1");
user.setAddress("天上人间");
user.setSex("男");
user.setBirthday(new Date());
//5.执行保存方法
userDao.insertUser(user);
}
[外链图片转存失败(img-oJC5rv9w-1565187691849)(C:\Users\45502\Desktop\assets\1559114946769.png)]
4.修改操作
第一步,编写IUserDao
/**
* 更新用户
* @param user
*/
void updateUser(User user);
第二步,编写IUserDao.xml
<!-- 更新用户 -->
<update id="updateUser" parameterType="com.itheima.domain.User">
update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday}
where id=#{id}
</update>
第三步,编写测试类
@Test
public void testUpdate(){
User user = new User();
user.setId(56);
user.setUsername("隔壁老王");
user.setAddress("隔壁的隔壁");
user.setSex("女");
user.setBirthday(new Date());
//5.执行保存方法
userDao.updateUser(user);
}
[外链图片转存失败(img-NkwJJnTd-1565187691851)(C:\Users\45502\Desktop\assets\1559115789667.png)]
5.删除操作
第一步,编写IUserDao
void deleteUser(Integer userId);
第二步,编写IUserDao.xml
<!-- 删除用户
如果说参数类型是原生类型,你可以直接写原生类型,而不需要全限名称
如果说参数类型是原生类型的话,那么sql语句中的参数可以随意起
-->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
第三步,编写测试类
/**
* 测试删除操作
*/
@Test
public void testDelete(){
//5.执行删除方法
userDao.deleteUser(56);
}
6.单一查询操作
第一步,编写IUserDao
User findById(int id);
第二步,编写IUserDao.xml
<!--单一查询-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id=#{id}
</select>
第三步,编写测试类
/*单一查询*/
@Test
public void testfindId(){
User user = userDao.findById(1);
System.out.println(user);
}
7.模糊查询操作
第一步,编写IUserDao
//模糊查询
List<User> findByName(String name);
第二步,编写IUserDao.xml
<!-- 根据名称模糊查询 -->
<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
select * from user where username like #{name}
</select>
第三步,编写测试类
//模糊查询
@Test
public void testdemo1(){
//5.执行删除方法
List<User> users = userDao.findByName("%王%");
for (User user : users) {
System.out.println(user);
}
}
注意:#{}和${}区别:
。#{}表示利用的预处理的执行对象PreparedStatment,专门用来防止sql注入攻击(建议使用)
。${}表示利用的statement对象,容易造成sql注入攻击(不建议使用)
8.新增之后立刻获取id操作
注意:使用场景,一般应用于电商项目中购物车中添加完购物车之后,要马上把当前购物车信息id添加到另外一张表中作为关联使用。
第一步,编写IUserDao
//新增
public void insertUser(User user);
第二步,编写IUserDao.xml
<!--新增
mybatis中赋值的时候需要使用#{}形式
注意:#{参数},参数写什么取决当前接口的参数类型
如果说参数类型是实体类类型的话,那么#{参数}参数必须要和实体类中的相对应的属性名称一致
注意:新增,修改和删除,以及查询的时候如果说需要参数,可以不去在标签只能加上parameterType,如果不加,mybatis
会自动去当前对应的dao接口方法中去匹配类型,建议还是要加上该属性
parameterType参数类型,属性值目前来说必须是全限名称
-->
<insert id="insertUser" parameterType="com.itheima.domain.User">
/*
selectKey表示查询主键的标签,一般应用于新增中,
keyProperty表示实体类中主键属性名称
keyColumn表示数据库表中的主键字段名称
resultType表示当前sql语句中的返回值类型
order表示当前sql语句插入的时机,
AFTER表示执行完新增sql语句之后开始执行该sql语句
BEFORE表示执行完新增sql语句之前开始执行该sql语句
*/
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID();
</selectKey>
INSERT INTO user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
第三步,编写测试类
/**
* 测试保存操作
*/
@Test
public void insertUser(){
User user = new User();
user.setUsername("二狗子1");
user.setAddress("天上人间");
user.setSex("男");
user.setBirthday(new Date());
System.out.println(user.getId());
//5.执行保存方法
userDao.insertUser(user);
System.out.println(user.getId());
}
9.传递 pojo 包装对象作为参数操作
第一步,编写QueryVo
/*
包装类对象
*/
public class QueryVo {
private User user;
第二步,编写IUserDao
//模糊查询
List<User> findByNameVo(QueryVo vo);
第三步,编写IUserDao.xml
<!-- 根据名称模糊查询queryVo
如果说参数类型是包装对象的话,那么sql语句中#{参数},参数等于包装对象里的属性名称.属性名称
-->
<select id="findByNameVo" parameterType="com.itheima.domain.QueryVo" resultType="com.itheima.domain.User">
select * from user where username like #{user.username}
</select>
第四步,编写测试类
//模糊查询2
@Test
public void testdemo2(){
QueryVo queryVo=new QueryVo();
User user=new User();
user.setUsername("%王%");
queryVo.setUser(user);
//5.执行删除方法
List<User> users = userDao.findByNameVo(queryVo);
for (User user2 : users) {
System.out.println(user2);
}
}
问题:表示IUserDao.xml中标签中的id属性值有重复的
10.实体类属性名称和数据库表字段名称不一致的操作
注意:如果实体类属性名称和数据库表字段名称一致的话,mybatis会映射不到
建议大家名称要一致。
不一致的解决方案:
第一步,创建一个实体类,属性名称和数据库表字段名称不一致
public class User2 implements Serializable{
private Integer uId;
private String uUsername;
private Date uBirthday;
private String uSex;
private String uAddress;
第二步,创建一个IUser2Dao
//全查
public List<User2> findAll();
第三步,创建一个IUser2Dao.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.itheima.dao.IUser2Dao">
<!--
resultMap标签表示结果集类型,
id属性表示当前标签的名称,不可重复
type表示表示当前结果集对应的类型,属性值等于domain类的全限名称
-->
<resultMap id="userResultMap" type="com.itheima.domain.User2">
<!--表示主键映射关系的标签
property表示实体类中的属性名称
column表示数据库表中的主键名称
javaType表示当前实体类中属性名称的类型,可以不写
jdbcType表示当前数据库表字段的类型,可以不写
-->
<id property="uId" column="id" javaType="Integer" jdbcType="INTEGER"></id>
<result property="uUsername" column="username"></result><!--非主键映射-->
<result property="uBirthday" column="birthday"></result><!--非主键映射-->
<result property="uSex" column="sex"></result><!--非主键映射-->
<result property="uAddress" column="address"></result><!--非主键映射-->
</resultMap>
<!--
在查询中有两个结果集属性:
1.resultType,
属性值很自由,可以是实体类对应的全限名称,还可以是类的类地址(int,long)
2.resultMap
属性值必须等于reusltMap标签的id属性值
注意:在同一个select标签中不可以同时出现resultMap和resultType属性
-->
<select id="findAll" resultMap="userResultMap">
SELECT * FROM user
</select>
</mapper>
第四步,测试
/**
* 测试查询所有
*/
@Test
public void findAll(){
//5.执行查询所有方法
List<User2> users = user2Dao.findAll();
for(User2 user : users){
System.out.println(user);
}
}
表示当前结果集中没有包含userResultMap1这个集合
[外链图片转存失败(img-vmYuDhgY-1565187691855)(C:\Users\45502\Desktop\assets\1559125451565.png)]
11.properties标签的使用
主要是为了分离代码,解决了一部分代码的耦合,一般应用于jdbc.properties
第一步,在当前项目中resources包下创建一个jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy_mybatis
jdbc.username=root
jdbc.password=123
第二步,修改sqlMapConfig.xml
<!--
引入外部的资源文件
resource表示获取类路径下的properties文件
-->
<properties resource="jdbc.properties"></properties>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
12.typeAliases和package标签的使用
修改sqlMapConfig.xml
<!--
别名库设置
-->
<typeAliases>
<!--一对一的别名设置,
type表示别名所对应的的类型
alias表示别名
-->
<!-- <typeAlias type="com.itheima.domain.User2" alias="user2"></typeAlias>
<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->
<!--
表示包扫描的形式
name属性表示实体类所在的路径地址
当前包路径下的所有的类都可以扫描到,使用的时候别名不区分大小写,建议大家使用类名
-->
<package name="com.itheima.domain"></package>
</typeAliases>
<!--核心配置文件去关联实体类映射文件-->
<mappers>
<!--
映射,resource表示路径,属性值必须是.xml文件所在的路径
注意:如果使用mapper形式去关联映射实体类映射文件,那么dao接口和实体类映射文件的名称可以不一致
因为是直接映射到.xml文件
-->
<mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
<mapper resource="com/itheima/dao/IUser2Dao.xml"></mapper>
<!--
表示扫描的是dao接口所在的包路径地址,当前包下的所有的接口类都可以被扫描到
那么dao接口和实体类映射文件的名称必须一致,因为包扫描是扫描的dao接口
-->
<!-- <package name="com.itheima.dao"></package>-->
</mappers>
main.User" alias=“user”>–>
<!--核心配置文件去关联实体类映射文件-->
<mappers>
<!--
映射,resource表示路径,属性值必须是.xml文件所在的路径
注意:如果使用mapper形式去关联映射实体类映射文件,那么dao接口和实体类映射文件的名称可以不一致
因为是直接映射到.xml文件
-->
<mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
<mapper resource="com/itheima/dao/IUser2Dao.xml"></mapper>
<!--
表示扫描的是dao接口所在的包路径地址,当前包下的所有的接口类都可以被扫描到
那么dao接口和实体类映射文件的名称必须一致,因为包扫描是扫描的dao接口
-->
<!-- <package name="com.itheima.dao"></package>-->
</mappers>