JavaWeb笔记二
MyBatis
什么是MyBatis?
MyBatis是一种框架,编写的是对数据保存到数据库的代码的框架。
MyBatis快速入门
创建模块,导入坐标
选择项目结构,添加新模块,然后选择添加maven项目。
接着创建模块。
在新创建的模块下找到pom.xml文件导入mybatis坐标
注意要导入多个依赖,则都要在dependencies标签里面,否则没有提示信息。
<dependencies>
<!-- mybatis的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <!-- mysql的依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> <scope>test</scope> </dependency> </dependencies>
编写mybatis的核心配置文件
作用是用来替换数据库连接信息的
去MyBatis的官网上的快速入门看从XML中构建SqlSessionFactory。
在项目src.main.resources下创建mybatis-config-xml文件。
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.cj.jdbc.Driver"/>
<!-- 连接数据库的信息--> <property name="url" value="jdbc:mysql://localhost:3306/数据库名字?useSSL=false&serverTimezone=UTC/> <property name="username" value="用户名"/> <property name="password" value="密码"/> </dataSource> </environment> </environments> <mappers>
<!-- 加载sql的映射文件--> <mapper resource="mapper文件的相对路径"/> <!-- Mapper代理包扫描的方式连接mysql的映射文件--> <package name="com.itheima.mapper"/></mappers></configuration>
sql映射文件的编写
在项目src.main.resources下创建sql映射文件。统一管理sql语句,解决硬编码问题
文件起名:表名Mapper.xml 例如orderMapper.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="test"> <select id="sql语句的唯一标识" resultType="sql语句对应类的相对路径"> select * from Blog where id = #{id} </select>
</mapper>
编写完sql映射文件之后需要在mybatis-config-xml文件里面填写sql映射文件的相对路径。
多行快捷键
alt+鼠标左键
User代码的编写
获取数据库上的数据
//alt+鼠标左键多行编辑
public class User { private int id; private String username; private String password; private String gender; private String addr;.......
MyBatisDemo代码的编写
得到sql语句的运行结果
public class MyBatisDemo { public static void main(String[] args) throws IOException { //1.加载mybatis配置文件,获取 SqlSessionFactory String resource = "mybatis-config.xml";//若是直接在resource根目录下,直接写文件名 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"); //空间名称.sql语句的idSystem.out.println(users); //4.释放资源 sqlSession.close(); }
}
执行时遇到这个问题: Exception in thread “main”org.apache.ibatis.exceptions.PersistenceException
跟着下面的链接大佬写的文章解决了。
附上原文链接idea运行mybatis出现Exception in thread “main” org.apache.ibatis.exceptions.PersistenceException等相关问题解决方案-CSDN博客
1.首先关注目录src/main/resources文件夹下的SqlMapConfig.xml文件
如果你的mysql时8.0以上的版本,有两个地方需要修改:
MySQL 8.0 以上版本 - JDBC 驱动名及数据库 URL:
com.mysql.cj.jdbc.Driver
和
jdbc:mysql://localhost:3306/runoob?useSSL=false&serverTimezone=UTC
注意:因为xml文件中,为避免错误的解析,&符号实际用&来表示
URL中的runoob是我自己建立的数据库的名称。
2.关注版本对应问题,这个也是比较难发现的点
将pom.xml文件夹下的mysql-connector-java更换一下版本号至8.0.16
Mapper代理开发(重点)
目的:解决mybatis编写代码中的硬编码问题。
Mapper代理开发的步骤
步骤一
定义sql的映射文件同名的Mapper接口,并将Mapper接口和sql映射文件置于同一目录下。
在MyBatis框架中,Mapper接口与其对应的XML映射文件的名称通常需要保持一致,但关于大小写问题有以下几点需要注意:
默认匹配规则
-
大小写敏感取决于操作系统:
-
在Windows系统上(不区分大小写):
UserMapper.java
可以匹配usermapper.xml
或UserMapper.xml
-
在Linux/Unix系统上(区分大小写):
UserMapper.java
必须严格匹配UserMapper.xml
-
-
最佳实践:
-
建议保持完全一致的大小写,包括首字母大小写
-
通常采用接口首字母大写,XML文件首字母大写的约定(如
UserMapper.java
和UserMapper.xml
)
-
同一目录下的问题
这个Mapper接口和sql映射文件是在同一目录下,但一般我们会把项目的Java文件和配置文件分开,因此这种方式不推荐。
可以在resources文件夹下创建与mapper接口相同的目录结构,项目编译之后,mapper接口和sql映射文件也会在同一目录下。
编译之后的字节码文件的结构只有java文件夹下的文件结构及编译之后的字节码文件和配置文件,其中配置文件若是在跟Java目录结构相同的情况下,那么在那个文件下面也有该配置文件,如下下图所示
在resources文件下创建目录不能用点,如下图所示
正确做法如下图
步骤二
设置sql映射文件的namespace属性为Mapper接口全限定名
步骤三
在Mapper接口中定义方法,方法名就是sql映射文件中sql语句的id,并保持参数类型和返回值一致。
注意上面该条语句是查询所有的数据那么返回的应该是一个User的集合类型。
最后因为改变了连接mysql的映射文件userMapper.xml的路径因此需要在mybatis-config.xml修改该路径。
<!-- Mapper代理包扫描的方式连接mysql的映射文件--> <package name="com.itheima.mapper"/>
步骤四
编码
//3.1获取userMapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();
System.out.println(users);
小细节
MyBatis配置文件
mybatis配置文件里面件包含了会深深影响 MyBatis 行为的设置和属性信息。
配置文档的顶层结构
配置文档的顶层结构如下:
环境配置(environments)
可以将sql映射到不同的数据库中。
映射器(mappers)
目的:解决mybatis编写代码中的硬编码问题。
类型别名(typeAliases)
可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases><package name="domain.blog"/>
</typeAliases>
每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author.
在配置各个标签的时候,需要遵守前后顺序。
对数据库数据完成增删改查(重点)
配置文件完成增删改查
练习
前置步骤
数据库表
-- 删除tb_brand表
drop table if exists tb_brand;
-- 创建tb_brand表
create table tb_brand
(-- id 主键id int primary key auto_increment,-- 品牌名称brand_name varchar(20),-- 企业名称company_name varchar(20),-- 排序字段ordered int,-- 描述信息description varchar(100),-- 状态:0:禁用 1:启用status int
);
-- 添加数据
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),('小米', '小米科技有限公司', 50, 'are you ok', 1);SELECT * FROM tb_brand;
实体类 Brand
package com.itheima.pojo; /** * 品牌 * * alt + 鼠标左键:整列编辑 * * 在实体类中,基本数据类型建议使用其对应的包装类型 */ public class Brand { // id 主键 private Integer id; // 品牌名称 private String brandName; // 企业名称 private String companyName; // 排序字段 private Integer ordered; // 描述信息 private String description; // 状态:0:禁用 1:启用 private Integer status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getBrandName() { return brandName; } public void setBrandName(String brandName) { this.brandName = brandName; } public String getCompanyName() { return companyName; } public void setCompanyName(String companyName) { this.companyName = companyName; } public Integer getOrdered() { return ordered; } public void setOrdered(Integer ordered) { this.ordered = ordered; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } @Override public String toString() { return "Brand{" + "id=" + id + ", brandName='" + brandName + '\'' + ", companyName='" + companyName + '\'' + ", ordered=" + ordered + ", description='" + description + '\'' + ", status=" + status + '}'; }
}
测试用例MyBatisTest
MyBatisX插件
提高开发效率
增删改查
最主要的三件事
sql语句怎么写?
完成某个功能要不要参数
完成之后返回怎样的结果
查询所有数据
MyBatisTest代码
public class MyBatisTest { @Test public void testSelectAll() throws IOException { //1.加载mybatis配置文件,获取 SqlSessionFactory String resource = "mybatis-config.xml";//若是直接在resource根目录下,直接写文件名 InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //2.获取sqlSession,用他来执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); //3.获取Mapper代理对象 BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); //4.执行方法 List<Brand> list = mapper.selectAll(); System.out.println(list); //5.释放资源 sqlSession.close(); } }
代码执行之后,返回的数据有的字段为null的解决方式
造成这种的原因是,sql片段#{}里面的数据名称与类的属性名不一样
在xxMapper.xml文件下编写修改下列代码
<!--namespace:名称空间-->
<mapper namespace="com.itheima.mapper.BrandMapper"> <resultMap id="brandResultMap" type="brand">
<!-- id 唯一标识 result 完成一般字段的映射 column:数据库字段名 property:java变量名
--> <result column="brand_name" property="brandName"/> <result column="company_name" property="companyName"/> </resultMap> <select id="selectAll" resultMap="brandResultMap"> select * from tb_brand; </select>
</mapper>
查看详情
<select id="selectById" parameterType="int" resultMap="brandResultMap"> //其中参数可以省略select * from tb_brand where id=#{id};
</select>
参数占位符的问题
*参数占位符
1.#{}:会将其替换为?为了防止sql注入
2.KaTeX parse error: Expected 'EOF', got '#' at position 42: … 1.参数传递时:#̲{} (常用) …{}
特殊字符问题
例如:select * from tb_brand where id<#{id};会报错,因为在xml文件下<是标签
解决方式:
1.转义字符
select * from tb_brand where id < #{id} //其中<是<的转义字符
2.CDATA区
select * from tb_brand where id <![CDATA[ 内容 ]]> #{id};
总结
条件查询(重要)
多条件查询
多条件查询接口参数编写的方法
方法一:为每个参数标上注解,注解里面的内容要和对应的sql语句里面占位符里面的内容一样。
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);//int status传递给Param里面的status的占位符
方法二:若传递的参数属于同一个对象,那么可以封装成一个对象,把对象传递到方法里面来。占位符里面的名称要和对象属性里的名称一样,不然找不到。
BrandMapper里面的核心代码
List<Brand> selectByCondition(Brand brand);Test里面的核心代码
//处理参数
companyName="%"+companyName+"%";
brandName="%"+brandName+"%";//封装对象
Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandName);//执行方法
List<Brand> brands = mapper.selectByCondition(brand);
方法三:把参数封装成map,map集合键的名称要和三个参数占位符名称保持一致。
BrandMapper里面的核心代码
List<Brand> selectByCondition(Map map);Test里面的核心代码
//Map对象
Map map=new HashMap();
map.put("status",status);
map.put("companyName",companyName);
map.put("brandName",brandName);
//执行方法
List<Brand> brands = mapper.selectByCondition(map);
多条件动态条件查询
编写动态sql语句来实现动态条件查询,解决用户只输入了一个条件查询的问题。
BrandMapper.xml核心代码<select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand <where> <if test="status!=null"> 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>
单条件动态条件查询
BrandMapper.xml核心代码
<select id="selectByConditionSingle" resultMap="brandResultMap"> select * from tb_brand <where> <choose> <when test="status!=null"> status=#{status} </when> <when test="companyName!=null and companyName!=' ' "> company_name like #{companyName} </when> <when test="brandName!=null and brandName!=' '"> brand_name like #{brandName}; </when> <otherwise> 1=1 </otherwise> </choose> </where>
</select>
注解完成增删改查
添加数据
BrandMapper.xml核心代码
<insert id="add"> insert into tb_brand(brand_name, company_name, ordered, description, status) value (#{brandName},#{companyName},#{ordered},#{description},#{status});
</insert>
Test核心代码//2.获取sqlSession,用他来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession(true);//注意这里要设置为true//4.执行方法
Brand brand = new Brand();
//获取参数
String brandName="小舞手机";
String companyName="凤凰集团";
int ordered=100000;
String description="渣成的小舞手机";
int status = 1;
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandName);
brand.setOrdered(ordered);
brand.setDescription(description);
mapper.add(brand);
返回添加数据的主键
BrandMapper.xml核心代码
<insert id="add" useGeneratedKeys="true" keyProperty="id">
Test核心代码
Integer id = brand.getId();
System.out.println(id);
修改全部字段
BrandMapper.xml核心代码
<update id="update"> update tb_brand set brand_name=#{brandName}, company_name=#{companyName}, ordered=#{ordered}, description=#{description}, status=#{status} where id=#{id};</update>
Test核心代码
Brand brand = new Brand();
//获取参数
String brandName="江南会所";
String companyName="凤凰集团";
int ordered=100000;
String description="颜麝的风华绝代";
int status = 1;
int id=1;
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setId(id);
int update = mapper.update(brand);
System.out.println(update);
修改动态字段
BrandMapper.xml核心代码
<update id="updateMove"> 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>
删除一个
BrandMapper.xml核心代码
<delete id="delete"> delete from tb_brand where id=#{id};
</delete>
删除多个
mybatis会将数组参数封装成一个Map集合
默认是:array=数组
使用@Param注解改变map集合默认的key的名称
BrandMapper.java核心代码
void deleteByIds(@Param("ids") int[] ids);
BrandMapper.xml核心代码
<delete id="deleteByIds"> delete from tb_brand where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach>
</delete>
或者
BrandMapper.java核心代码
void deleteByIds(int[] ids);
BrandMapper.xml核心代码
<delete id="deleteByIds"> delete from tb_brand where id in <foreach collection="array" item="id" separator="," open="(" close=")"> #{id} </foreach>
</delete>
MyBatis参数传递
多个参数
封装为Map集合,使用@Param注解,替换Map集合中默认的arg键名。Param(“这里名字要和sql语句里#{}里面的一样”)