Mybatis(1)
使用原生JDBC的问题
- 数据库连接使用时创建,不使用时关闭,对数据库进行频繁的开启和关闭,造成了数据库资源的浪费,影响数据库性能
使用数据库连接池进行管理数据库连接
- 将SQL语句硬编码到java代码内,如果SQL语句修改,需要重新编译,不利于系统维护
将SQL语句配置到XML文件内
- 向preparedStatemment中设置参数,对于占位符和参数硬编码在java代码内,不利于维护
配置在XML文件内
- resultSet结果集数硬编码于Java代码内
将结果自动映射成java对象
Mybatis 框架(持久层的框架)
- Mybatis 下载
- Mybatis 文档
- Mybatis 流程图
入门程序
- 根据主键查询信息
- 根据用户名称模糊查询
- 增、删、查、改
根据用户ID查询信息
创建Mybatis配置文件
- 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="development">
<environment id="development">
<!-- 使用了JDBC的事务管理,事务控制有Mybatis-->
<transactionManager type="JDBC"/>
<!-- 数据库链接池,由Mybatis管理-->
<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>
创建映射文件(Mapper)
- 命名方式:XXXmapper.xml
- usermapper.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">
<!--命名空间,作用是对Sql进行父类管理(SQL的隔离)-->
<mapper namespace="com.test.user">
<!-- 在映射文件内配置多个SQL语句-->
<!-- 查询
id:标识映射文件内的SQL,称为statement的id(将来SQL语句会封装到mapperSatement对象内)
#{} 表示一个占位符,#{id} 内的id表示接受的参数名称为id
parameterType 指定输入参数的类型
resultType 指定SQL返回的结果所映射的java对象的类型
-->
<select id="findUserById"
parameterType="int"
resultType="com.pojo.User">
select * from user where id = #{id}
</select>
</mapper>
创建POJO类(普通javaBean)
package com.pojo;
public class User {
// 属性名要和java字段对应
private Integer id;
private String username;
private String password;
private String name;
private String sex;
private String 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 getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
在SqlMapConfig.xml 内记载Mapper文件
<mappers>
<mapper resource="Mapper 文件路径"/>
</mappers>
编写代码
package com.mybatisStudy1;
import com.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.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
/**
* Hello world!
*
*/
public class App {
// 根据id查询用户信息
@Test
public void test() throws IOException {
// 创建会话工厂
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
// 通过工厂获取SqlSession
SqlSession ss = ssf.openSession();
// 操作数据库
// selectOne(String statement, Object parameter);
// statement:映射文件内statement的id, 值为mapper的命名空间(namespace)和SQL id
// parameter:输入的参数(类型要和parameterType所写的类型匹配)
// 返回resultType内所写类型的对象
User user = ss.selectOne("com.test.user.findUserById",
1);
System.out.println(user.toString());
// 释放资源
ss.close();
is.close();
}
}
根据用户名称模糊查询信息
创建mapper文件
<?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">
<!--命名空间,作用是对Sql进行父类管理(SQL的隔离)-->
<mapper namespace="com.test.user">
<!-- 在映射文件内配置多个SQL语句-->
<!-- 查询
id:标识映射文件内的SQL,称为statement的id(将来SQL语句会封装到mapperSatement对象内)
#{} 表示一个占位符,#{id} 内的id表示接受的参数名称为id
parameterType 指定输入参数的类型
resultType 指定SQL返回的结果所映射的java对象的类型
-->
<select id="findUserById"
parameterType="int"
resultType="com.pojo.User">
select * from user where id = #{id}
</select>
<!-- resultType:指定的就是单条记录所映射的java类型-->
<!-- ${}:表示拼接sql串,将接受到的内容不加任何修饰拼接到sql中
可能会引起SQL注入
如果传入的是简单类型参数,则${}内只能写成value - ${value}
-->
<select id="findUserByName"
parameterType="string"
resultType="com.pojo.User">
select * from user where name like '%${value}%'
</select>
</mapper>
编写程序
@Test
public void testFindUserByName() throws IOException {
// 创建SQL 会话工厂
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
// 创建会话
SqlSession ss = ssf.openSession();
// 操作数据库 --- 使用${} 存在sql注入的风险
List<User> users = ss.selectList("findUserByName", "铁");
for (User u:users
) {
System.out.println("【RESULT】:" + u.toString());
}
// 释放资源
ss.close();
is.close();
}
添加用户
mapper 文件
- 配置添加用户的Statement
OGNL
<!-- 添加用户
parameterType:指定输入的类型是pojo(包括用户信息)
#{}:内写指定的pojo的属性名,接受到pojo的属性值
(mybatis是使用OGNL获取对象的属性值)
-->
<insert id="addUser"
parameterType="com.pojo.User">
insert into user (id, username, password, name, sex, addr)
values (#{id},#{username},#{password},#{name},#{sex},#{addr});
</insert>
编写代码
@Test
public void testAddUser() throws IOException {
// 创建SqlSessionFactory
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
// 创建SqlSession
SqlSession ss = ssf.openSession();
// 操作数据库
System.out.println(ss.insert("addUser", new User(null, "12131", "12131", "上官翠花", "女", "公主坟")));
ss.commit();
// 释放资源
ss.close();
is.close();
}
- 在执行insert提交之前生成一个自增主键
SELECT LAST_INSERT_ID()
在Insert之后调用
<insert id="addUser"
parameterType="com.pojo.User">
/*
将插入的数据的主键值返回到User对象内
SELECT LAST_INSERT_ID():得到 insert 进去记录的主键值(只适用于自增)
_**selectKey:查询数据库内某一个属性的值,并且将查询的值赋值给keyProperty内声明的属性
keyProperty:将查询结果设置到parameterType指定对象的哪个属性
order:相对于当前SQL语句的执行顺序(执行前BEFORE/执行后AFTER)**_
*/
<selectKey keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
/*执行后结果 User{id=null, username='12131', password='12131', name='欧阳铁柱', sex='女', addr='公主坟'}*/
<!--<selectKey order="AFTER" resultType="com.pojo.User" keyProperty="name" >
select * from user where username = '12138'
</selectKey>
-->
insert into user (id, username, password, name, sex, addr)
values (#{id},#{username},#{password},#{name},#{sex},#{addr});
</insert>
- 非自增主键的返回(Mysql)
- 使用
SELECT UUID()
获取(条件:表中id字段类型为varchar,长度为35)- 执行过程:
- 先通过UUID()查询到主键,再将主键设置到sql语句中(设置到#{id})
- 执行UUID()在insert语句之前
- usertempuuid_mapper.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.pojo.User_temp_uuid_">
<insert id="addUser"
parameterType="com.pojo.User_temp_uuid_">
/*
resultType:返回类型,返回值会赋值给INSERT语句内的#{id}
*/
<selectKey order="BEFORE" keyProperty="id" resultType="string">
SELECT UUID()
</selectKey>
INSERT INTO user_temp_uuid_(id, name)
value (#{id}, #{name})
</insert>
</mapper>
@Test
public void testAddUserUUID() throws IOException {
// 创建SqlSessionFactory
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
// 创建SqlSession
SqlSession ss = ssf.openSession();
// 创建实体类对象
User_temp_uuid_ utu = new User_temp_uuid_("1", "欧阳铁柱");
// 操作数据库
ss.insert("com.pojo.User_temp_uuid_.addUser", utu);
System.out.println(utu.toString());
// 提交事务
ss.commit();
// 释放资源
ss.close();
is.close();
}
- 执行结果
删除用户/更新用户
mapper配置
<!-- 删除用户-->
<delete id="deleteUser" parameterType="int">
DELETE FROM USER where id = #{id}
</delete>
<!-- 更新用户
#{id}:从输入的user对象内获取id属性的值 -->
<update id="updateUser" parameterType="com.pojo.User">
update user set username = #{username}, password = #{password}, name = #{name}, sex = #{sex}, addr = #${addr}
where id = #{id}
</update>
编写代码
// 删除用户
@Test
public void deleteUser() throws IOException {
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("deleteUser", 15);
sqlSession.commit();
sqlSession.close();
is.close();
}
// 更新用户
@Test
public void updateUser() throws IOException {
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.update("updateUser", new User(3, "11221", "11221", "小崔", "男", "蓬莱路"));
sqlSession.commit();
sqlSession.close();
is.close();
}
总结
parameterType
- 在映射文件内通过parameterType指定输入参数的类型
resultType
- 在映射文件内通过resultType指定输出结果的类型
#{}和${}
- #{}:表示占位符
- ${}:表示拼接符 — 存在SQL注入的风险,不建议使用
selectOne() 和 selectList()
- selectOne():查询一条记录进行映射
- selectList():查询出一个列表(多条记录)来进行映射