迭代更新,更新时代
时代发展,发展技术
技术进步,进步迭代
——Lungcen
目录
MyBatis的简介入门
1、硬编码
2、操作繁琐
MyBatis简单入门
1、处理硬编码
2、处理操作繁琐
3、参数传递
MyBatis核心配置文件
配置文档的顶层结构
环境配置(environments)
类型别名(typeAliases)
Mapper代理开发
小动作
1、自动封装
2、特殊字符
通过Mapper代理开发的参数传递
1、单参数
2、多参数
1、注解的方式
2、传一个封装对象类
3、传一个Map集合
MyBatis的简介入门
什么是mybatis呢?它是一个持久层框架,用来简化JDBC开发。了解持久层就需要知道Java的三层架构(例如:SSM框架、SSH框架)
框架:是一个半成品的软件、一套可以重用、通用、软件基础代码模型
SSM架构,是三层结合所成的框架,分别是Spring、SpringMVC、MyBatis所组成
SSH框架,是JAVA EE中三种框架所集成,分别是Struts,Spring,Hibernate框架所组成
Java中三层架构:表现层、业务层、持久层
业务层(代码逻辑)
处理业务逻辑、处理一个业务的过程逻辑(运行逻辑、过程设计)
表现层(前端显示)
接收请求并且展示数据,将一个业务层的业务展现出来,通常使用MVC模型来设计(展示界面、界面设计)持久层(数据库)
数据库交互,对一个业务进行操作时数据的处理(数据存储和处理、数据设计)
简化JDBC的开发,那JDBC有什么需要简化的呢?
我们来将之前用JDBC写的代码分解来看有一下两种问题
1、硬编码
建立与数据库的连接,都需要写下面这段重复的代码,而且如果需要更改用户名和用户密码就需要改动代码(维护性稍差)
我们这种没有编译、打包的,到还好,可以直接上手改代码、那种已经编译、打包过的,就需要改为代码后重新编译、打包、运行。
//获取配置文件的方法
Properties prop = new Properties();
//加载配置文件
prop.load(new FileInputStream("src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取连接
Connection conn = dataSource.getConnection();
同上面修改密码一样的原因,SQL语句是写死的,改SQL语句就要需要动代码(那个int id = 1,是手动传的参,就没有从前端获取了,为了方便学习嘛)
int = 1;
//定义SQL
String sql = "select * from tb_brand where id = ?";
2、操作繁琐
我们为了防止SQL注入,使用了预编译的方式运行SQL语句,所以就需要手动设置参数,传值替代问号。传值的个数少到还好、一旦多起来就很繁琐
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//传入参数
pstmt.setString(1, id);
//执行SQL
ResultSet rs = pstmt.executeQuery();
手动封装结果集也是一个操作繁琐的步骤,这么多代码不仅难写还容易出错
//处理结果
List<Object> list = new ArrayList<>();
while(rs.next()){
int id = rs.getInt("id");
String brandName = rs.getString("brand_name");
String companyName = rs.getString("company_name");
int ordered = rs.getInt("ordered");
String description = rs.getString("description");
int status = rs.getInt("status");
Brand brand = new Brand();
brand.setId(id);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setStatus(status);
list.add(brand);
}
System.out.println(list);
//释放资源
rs.close();
pstmt.close();
conn.close();
MyBatis简单入门
mybatis – MyBatis 3 | 入门https://mybatis.org/mybatis-3/zh/getting-started.html
通过Maven配置Mybatis的jar包
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency>
连接数据库,需要导入Mysql的驱动
<!--添加mysql依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.22</version> </dependency>
需要导入 测试类 来测试代码
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency>
编写mybatis-config.xml文件(配置文件)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>
这里是配置数据库连接信息
<property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/>
1、处理硬编码
指定SQL映射文件(上面处理了数据库连接信息的硬编码,这里处理SQL语句的硬编码)
<mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers>
处理SQL语句的配置文件的命名也是有规范的,我们是使用Mapper代理开发的,假如操作User表,就取名为UserMapper.xml,同理,处理Xxxx表,就取名XxxxMapper.xml。我们目前需要操作User表,就命名为UserMapper.xml
<mapper>标签中namespace是指名称空间,不可省略的,作用是:当存在多个XxxxMapper时,并且可能会存在同样的方法,那么就可以通过 XxxxMapper.id里的内容 来找到对应的SQL语句
<select>标签中id是SQL语句的唯一标识、resulType是返回值的类型(例如列表、int、一个封装的对象啥的……)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.mybatis.example.BlogMapper"> <select id="selectBlog" resultType="Blog"> select * from Blog where id = #{id} </select> </mapper>
既然存在了SQL的映射文件,那么我们就可以把mybatis-config.xml文件中关于配置SQL映射文件的地方给修改一下
如果配置文件mybatis-config.xml和SQL映射文件UserMapper.xml在同一级,那么可以直接写UserMapper.xml,不过由于编码的一些原因,不建议这么写
<mappers> <mapper resource="com/zpark/mapper/UserMapper.xml"/> </mappers>
当SQL的映射文件多了起来的时候,就需要写很多条,这是一个很繁琐的步骤!
加载SQL映射文件这块,除了这么写,当你使用了Mapper代理开发后,可以使用包扫描的方式来加载SQL语句,使用 包加载 后就可以直接扫描整个包,而不是像上面那个一个一个的加载
<mappers> <package name="com.zpark.mapper"/> </mappers>
到这一步,基本上就消除了JDBC的硬编码问题,通过配置文件来改变与数据库的连接、通过SQL映射文件来修改SQL语句写死的问题,那目前还有操作繁琐问题的勒!
2、处理操作繁琐
对于操作繁琐的问题:
1、定义POJO类,来封装从数据库的信息
2、加载配置文件、获取SqlSessionFactory对象
3、获取SqlSession对象、执行SQL语句
4、释放前面获取的资源
定义POJO类、设置get、set方法、重写toString方法、构造方法
package com.zpark.pojo; public class User { private Integer id; private String username; private String password; private String gender; private String addr; public User(Integer id, String username, String password, String gender, String addr) { this.id = id; this.username = username; this.password = password; this.gender = gender; this.addr = addr; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", gender='" + gender + '\'' + ", addr='" + addr + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } }
有了User类后,那么我们就可以封装数据库获取的数据,那么对于SQL映射文件就可以改一下(这里就自动把数据封装了)
<?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="test"> <select id="selectAll" resultType="com.zpark.pojo.User"> select * from tb_user </select> </mapper>
加载配置文件、获取对象(这里我们没有手动封装结果集,也能封装到对象中)
public static void main(String[] args) throws IOException { //加载配置文件、获取sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //获取sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> users = sqlSession.selectList("test.selectAll"); System.out.println(users); sqlSession.close(); }
3、参数传递
单参数:当 SQL语句需要参入一个参数时,需要添加一个parameterType属性表示传入参数的值类型,然后参数对应位置需要用 #{参数名} 表示
<mapper namespace="test"> <select id="selectAll" parameterType="int" resultType="com.zpark.pojo.User"> select * from tb_user where id = #{id} </select> </mapper>
传入参数则在执行SQL语句的时候
SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> users = sqlSession.selectList("test.selectAll", 2);
多参数:由于mybatis的只支持设置一个paremeterType;所以如果要传递多个数值,单靠一个基础的数据类型是无法承载的。
遇到需要传递多个参数的时候,将parameterType设置成Map接口类型,利用对应的键值对,来设置多个参数
<mapper namespace="test"> <select id="selectAll" parameterType="map" resultType="com.zpark.pojo.User"> select * from tb_user where id = #{id} and username = #{username} </select> </mapper>
qlSession sqlSession = sqlSessionFactory.openSession(); Map map = new HashMap(); map.put("id",1); map.put("username", "三"); List<User> users = sqlSession.selectList("test.selectAll", map);
MyBatis核心配置文件
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
配置文档的顶层结构
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
在配置各个标签时,需要严格的遵守前后顺序
环境配置(environments)
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。
简单理解就是,先配置好多个可能用到的数据库,但你需要使用哪个数据库就将 <environments default="development"> 中的default值 改成 你所需要的数据库的 id
<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/db1> <property name="username" value="Lungcen"/> <property name="password" value="123123"/> </dataSource> </environment> <environment id="kaifa"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/db2"/> <property name="username" value="Lungcen"/> <property name="password" value="232323"/> </dataSource> </environment> </environments>
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境, 每个数据库对应一个 SqlSessionFactory 实例。所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推。
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。这样就可以在使用 domain.blog.Author 的地方用 Authour 来替代
<typeAliases> <typeAlias alias="Author" type="domain.blog.Author"/> </typeAliases>
可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 com.zpark.pojo.User
的别名为 user
<typeAliases> <package name="com.zpark.pojo.User"/> </typeAliases>
其他的标签可以进入这个网址了解详情
mybatis – MyBatis 3 | 配置https://mybatis.org/mybatis-3/zh/configuration.html
Mapper代理开发
解决了在Mybatis中出现的两个问题
1、 解决MyBatis的硬编码问题
2、简化后期执行SQL
使用Mapper代理开发需要满足下面几点要求
1、定义一个与SQL映射文件同名的Mapper接口,并且需要将Mapper接口和SQL映射文件在同一个目录下
2、设置SQL映射文件的namespace属性为Mapper接口全限定名
3、在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保存参数类型和返回值类型一致(插件MyBatisX可以更加轻松的解决)
4、通过SqlSession的getMapper方法获取Mapper接口的代理对象,然后完成SQL的执行
要求1:在同一个文件目录下
需要将Mapper接口 和 SQL映射文件在同一个目录
1、直接放在同一个包下
2、在resource中建一个和Mapper接口一样的包结构来放SQL映射文件(编译的时候会合并同的)
图中java包中的UserMapper就是Mapper接口
图中resource包中的UserMapper.xml就是SQL映射文件
图中resource包中的mybatis-config.xml就是mybatis配置文件
要求2:SQL映射文件中的命名空间(namespace属性)为Mapper接口全限定名
<mapper namespace="com.zpark.mapper.UserMapper"> <select id="selectAll" resultType="com.zpark.pojo.User"> select * from tb_user </select> </mapper>
要求3:在Mapper接口中定义方法
例如上面图片那个方法,定义了SQL的一个selectAll方法、返回值是User对象,那么在Mapper接口中就需要一个名为 selectAll ,返回值为 User 的方法
MyBatisX插件可以 实现XML中的SQL方法 和 接口中的方法 之间进行跳转,就不用来回翻;可以根据在接口中写的方法来 在XML中自动生成 statement 框架,SQL语句还是要自己写的
public interface UserMapper { List<User> selectAll(); }
使用Mapper代理开发的运行代码
public static void main(String[] args) throws IOException { //加载配置文件、获取sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //获取sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.selectAll(); System.out.println(users); sqlSession.close(); }
小动作
1、自动封装
1、封装对象设置的属性名称和数据库中的列名不一致会导致无法自动封装,需要一些小动作
1、设置别名(处理SQL)
通过SQL语句的as 将设置的别名和封装对象中的属性名一致
2、进行映射(处理MyBatis)
写在BrandMapper.xml文件中,因为SQL语句是在SQL映射文件中执行,而BrandMapper.xml就是SQl映射文件,所以才写在其中
<resultMap>中有两个子标签
一个是<id>对应主键的映射
另一个是<result>对应普通字段的映射
<resultMap id="brandMap" type="brand">
<result column="brand_name" property="brandName"></result>
<result column="company_name" property="companyName"></result>
</resultMap>
id :是唯一标识、指向这个映射
type :是映射的类型,指向封装对象
colum :是列名,指向数据库的列名
property :是属性名,指向封装对象的属性
设置了映射,就在使用到的SQL语句中使用,将原来的 resultType="com.zpark.pojo.Brand" 替换成 resultMap="brandMap"
<select id="selectAll" resultMap="brandMap">
select *
from tb_brand
</select>
2、特殊字符
2、在SQL语句中,会存在一些特殊字符的问题,例如需要写 id < 2,如果只看SQL是没有问题的,但是我们是写在XML文件中,他会识别 < 为 标签 的一部分,所以需要进行特殊处理
1、老办法、或者潜意识的办法,进行转义,例如 < 转义为 <
2、CDATA区,以"<![CDATA[ "开始,以" ]]>" 结束,在两者之间写不想被解析程序解析的代码,解析器是不对CDATA区中的内容进行解析
通过Mapper代理开发的参数传递
1、单参数
用#{id} 来接收id
除了#{id}外,还可以用${id},前者可以看成预编译,后者则是SQL语句进行拼接
<select id="selectAll" resultMap="brandMap">
select *
from tb_brand where id = #{id}
</select>
SQL映射文件更改后需要一个参数,那么在Mapper接口中设置一个形式参数
public interface BrandMapper {
List<Brand> selectAll(int id);
}
如此,调用的时候,只需要在后面添加一个实参就行
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
List<Brand> users = mapper.selectAll(1);
2、多参数
类比单参数的过程,修改SQL语句再添加几个参数,Mapper接口中填入多个形参,调用的时候传入多个实参。但是这个是错误的,Mapper代理开发不支持这样使用
1、注解的方式
SQL映射文件:关于SQL语句的书写,用多个占位符来给参数占位子
<select id="selectOne" resultMap="brandMap"> select * from tb_brand where id = #{id} and status = #{status} </select>
Mapper接口文件:利用Param注解就进行注解
public interface BrandMapper { List<Brand> selectOne(@Param("id") int id, @Param("status") int status); //注解 // List<Brand> selectOne(Brand brand); //对象 // List<Brand> selectOne(Map map); //集合 }
测试文件:获取SqlSessionFactory对象,然后获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); List<Brand> brands = mapper.selectOne(1, 1); System.out.println(brands);
2、传一个封装对象类
注意:对象的属性名称需要和参数占位符一样
SQL语句不需要改变、只要改动Mapper接口 和 调用方法的地方,修改实参和形参
public interface BrandMapper { List<Brand> selectAll(int id); List<Brand> selectOne(Brand brand); //对象 // List<Brand> selectOne(Map map); //集合 }
调用方法,由于是传入一个对象,所以需要先实例一个对象,然后按照SQL来设置值,最后在传入方法中去执行
SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); Brand brand = new Brand(); brand.setId(1); brand.setStatus(1); List<Brand> brands = mapper.selectOne(brand); System.out.println(brands);
3、传一个Map集合
注意:
SQL语句依旧不需要进行改动,只需要改动其他两个文件
public interface BrandMapper { List<Brand> selectAll(int id); List<Brand> selectOne(Map map); //集合 }
SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); Map map = new HashMap(); map.put("id", 1); map.put("status", 1); List<Brand> brands = mapper.selectOne(map); System.out.println(brands);
迭代更新,更新时代
时代发展,发展技术
技术进步,进步迭代
——Lungcen