SSM之Mybatis_ch3
XML映射文件细解(一)
- cache——命名空间的缓存配置
- cache-ref——引用其他命名空间的缓存配置
- resultMap——从数据库结果集中加载对象,是最复杂也最强大的元素
- sql——可被其他语句引用的可重用语句块
- insert——映射插入语句
- update——映射更新语句
- delete——映射删除语句
- select——映射查询语句
此篇只讲述select、insert、update、delete以及resultMap入门。
select
<select id="getUser" parameterType="int" resultType="com.reflect.pojo.User">
select * from mybatis.user where id=#{id}
</select>
- id为getUser(对应UserMapper接口中的方法名)
- parameterType:参数类型。接收一个int(或Integer)类型的参数
- resultType:查询出的结果集的类型
#{id} 类似于JDBC中的PreparedStatement中的"?"参数传递id
i d 在 M y B a t i s 中 也 有 ‘ {id} 在MyBatis中也有` id在MyBatis中也有‘{}`,但是无法保证安全性。不推荐使用
即#{id}能防止SQL注入,而${id}不能。
以下列出select常用的部分属性,其他可访问MyBatis官网进行参考。
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句 |
parameterType | 传入这条语句的参数的类全限定名或别名。此属性是可选的 |
resultType | 从这条语句中返回结果的类全限定名或别名。如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型 |
resultMap | 对外部 resultMap 的命名引用。resultType 和 resultMap 之间只能同时使用一个 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false |
useCache | 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset) |
insert, update 和 delete
三者十分相似,只是实现的功能不同。
(其实不管用insert/update/delete哪个标签都无所谓,主要是其中的sql语句起作用,但是一般遵从规则,才使得三者分别对应不同的sql语句来执行不同的功能)
<insert id="insertUser" parameterType="com.reflect.pojo.User">
insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>
<update id="updateUser" parameterType="com.reflect.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
</update>
<delete id="deleteUser" parameterType="com.reflect.pojo.User">
delete from mybatis.user where id=#{id}
</delete>
以下列出三者常用的部分属性,其他可访问MyBatis官网进行参考。
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句 |
parameterType | 传入这条语句的参数的类全限定名或别名,此属性是可选的 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset) |
useGeneratedKeys | 仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset )。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
keyColumn | 仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
插曲——分页
1、通过MySQL数据库的Limit
关键字实现分页
<!--UserMapper.xml中-->
<!--分页1-->
<select id="getUserByLimit" parameterType="map" resultType="com.reflect.pojo.User">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
// 分页1:通过查询数据库进行分页,此处只是mysql的分页,其他数据库可能不支持
@Test
public void getUserByLimit() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Integer> map = new HashMap<>();
map.put("startIndex",0);
map.put("pageSize",2);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
最终运行结果:
2、通过Java代码实现分页
<!--UserMapper.xml中-->
<!--分页2-->
<select id="getUserByRowBounds" resultType="com.reflect.pojo.User">
select * from mybatis.user;
</select>
// 分页2:通过Java代码层面进行分页
@Test
public void getUserByRowBounds() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
// RowBounds实现
RowBounds rowBounds = new RowBounds(1,2);
// 通过java代码实现分页
List<User> userList = sqlSession.selectList("com.reflect.mapper.UserMapper.getUserByRowBounds",null,rowBounds);
for (User user : userList) {
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
最终运行结果:
插曲——日志的示例
<!--mybatis-config.xml中-->
<!--配置日志文件 建议从官网复制logImpl,可能会出错-->
<settings>
<!--标准日志工厂实现-->
<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
<setting name="logImpl" value="LOG4J"/>
</settings>
#log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/reflect.log
log4j.appender.file.MaxFileSize = 10MB
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = [%p][ghost%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis = DEBUG
log4j.logger.java.sql = DEBUG
log4j.logger.java.sql.Statement = DEBUG
log4j.logger.java.sql.ResultSet = DEBUG
log4j.logger.java.sql.PreparedStatement = DEBUG
之后的随意运行一个Test方法,将会在当前项目下新建一个log目录reflect.log,不断往其中追加内容。控制台也会打印出相关内容
resultMap
初步入门:
resultMap能很好地解决属性名与数据库中字段名不一致的情况。
一般情况下,可以使用如下取别名方式:
<!--数据库中字段一般有下划线,因为一般数据库字段名一般小写-->
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id}
</select>
如上所示的select简单语句并没有显式配置结果映射,MyBatis会在幕后自动创建一个resultmap,再根据属性名来映射到pojo中的JavaBean中属性上。如下所示:
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
综合一下,实际上显示配置resultMap就是如下所示:
<!--此处的type应该为com.reflect.pojo.User,但已经在配置文件中将pojo包进行配置,
故此处直接使用User,Mybatis将会在使用JavaBean时自动到pojo包下寻找-->
<resultMap id="UserMap" type="User">
<!--property对应实体类中的属性,column对应数据库中的字段名-->
<!--当只有某些属性与字段不重名,只需要单独配置这些属性与字段的关系即可-->
<result property="pwd" column="pwd"/>
</resultMap>
<select id="getUser" parameterType="int" resultMap="UserMap">
select * from mybatis.user where id=#{id}
</select>
高级映射:
见第五篇文章
全部代码
项目结构图
1.新建User.java
package com.reflect.pojo;
import org.apache.ibatis.type.Alias;
/**
* author: Administrator
* date: 2020/12/30 - 22:56
*/
// 这是第三种取别名方式
@Alias("user")
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
2.新建UserMapper.java
package com.reflect.mapper;
import com.reflect.pojo.User;
import java.util.List;
import java.util.Map;
/**
* author: Administrator
* date: 2020/12/30 - 22:57
*/
public interface UserMapper {
// 查询单个用户
User getUser(int id);
// 新增一个用户
boolean insertUser(User user);
// 修改一个用户
boolean updateUser(User user);
// 删除一个用户
boolean deleteUser(int id);
//分页1
List<User> getUserByLimit(Map<String,Integer> map);
//分页2
List<User> getUserByRowBounds(Map<String,Integer> map);
}
3.新建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">
<!--namespace绑定一个对应的mapper接口-->
<mapper namespace="com.reflect.mapper.UserMapper">
<!-- <select id="getUser" parameterType="int" resultType="com.reflect.pojo.User">-->
<!-- select * from mybatis.user where id=#{id}-->
<!-- </select>-->
<!-- 分页1-->
<select id="getUserByLimit" parameterType="map" resultType="com.reflect.pojo.User">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
<!-- 分页2-->
<select id="getUserByRowBounds" resultType="com.reflect.pojo.User">
select * from mybatis.user;
</select>
<insert id="insertUser" parameterType="com.reflect.pojo.User">
insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>
<update id="updateUser" parameterType="com.reflect.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
</update>
<delete id="deleteUser" parameterType="com.reflect.pojo.User">
delete from mybatis.user where id=#{id}
</delete>
<!-- 此处的type应该为com.reflect.pojo.User,但已经在配置文件中将pojo包进行配置,
故此处直接使用User,Mybatis将会在使用JavaBean时自动到pojo包下寻找-->
<resultMap id="UserMap" type="User">
<!-- property对应实体类中的属性,column对应数据库中的字段名-->
<result property="pwd" column="pwd"/>
</resultMap>
<select id="getUser" parameterType="int" resultMap="UserMap">
select * from mybatis.user where id=#{id}
</select>
</mapper>
4.新建MybatisUtils.java
package com.reflect.utils;
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 java.io.InputStream;
/**
* author: Administrator
* date: 2020/12/30 - 22:52
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
5.新建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>
<properties resource="dbconfig.properties">
</properties>
<!--配置日志文件 建议从官网复制logImpl,可能会出错-->
<settings>
<!--标准日志工厂实现-->
<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
<setting name="logImpl" value="LOG4J"/>
</settings>
<typeAliases>
<package name="com.reflect.pojo"/>
</typeAliases>
<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>
<!-- 此处的resource要注意是'/',而不是'.'-->
<mappers>
<mapper resource="com/reflect/mapper/UserMapper.xml"/>
</mappers>
</configuration>
6.新建dbconfig.properties
driver=com.mysql.cj.jdbc.Driver
#url中&在配置文件可以直接写,但是在程序中需要进行可能转义
url=jdbc:mysql://192.168.199.131:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
7.新建log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/reflect.log
log4j.appender.file.MaxFileSize = 10MB
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = [%p][ghost%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis = DEBUG
log4j.logger.java.sql = DEBUG
log4j.logger.java.sql.Statement = DEBUG
log4j.logger.java.sql.ResultSet = DEBUG
log4j.logger.java.sql.PreparedStatement = DEBUG
8.新建Test类进行测试
import com.reflect.mapper.UserMapper;
import com.reflect.pojo.User;
import com.reflect.utils.MybatisUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* author: Administrator
* date: 2020/12/30 - 23:01
*/
public class MyTest {
// 查询单个用户
@Test
public void getUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUser(1);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
// 分页1:通过查询数据库进行分页,此处只是mysql的分页,其他数据库可能不支持
@Test
public void getUserByLimit() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Integer> map = new HashMap<>();
map.put("startIndex",0);
map.put("pageSize",2);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
// 分页2:通过Java代码层面进行分页
@Test
public void getUserByRowBounds() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
// RowBounds实现
RowBounds rowBounds = new RowBounds(0,2);
// 通过java代码实现分页
List<User> userList = sqlSession.selectList("com.reflect.mapper.UserMapper.getUserByRowBounds",null,rowBounds);
for (User user : userList) {
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
// 新增一个用户
@Test
public void insertUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int id = (int) (Math.random()*1000000000);
String string = UUID.randomUUID().toString();
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
boolean res = mapper.insertUser(new User(id, string, "pwd"+string));
if (res) {
System.out.println("插入成功!!!");
}
// 提交事务(即使打印出成功结果,不提交也是不会插入数据库)
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
// 修改一个用户
@Test
public void updateUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
String string = UUID.randomUUID().toString();
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
boolean res = mapper.updateUser(new User(2,string,"pwd"+string));
if (res) {
System.out.println("修改成功!!!");
}
// 提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
// 删除一个用户
@Test
public void deleteUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
boolean res = mapper.deleteUser(2);
if (res) {
System.out.println("删除成功!!!");
}
// 提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}