赞
踩
JDBC使用大致步骤
由于JDBC操作过于复杂繁琐,于是就产生了对象关系映射(Objec Relational Mapping,简称ORM,OR mapping)
<!-- POJO和映射关系 -->
<class name ="com.example.po.User" table = "user">
<id name = "id" type = "long">
<column name = "id" />
</id>
<property name = "userName" type = "string">
<column name = "user_name" length = "32"/>
</property>
</class>
<?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"> <property name="autoCommit" value="false"/> </transactionManager> <!-- 数据源 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!-- 映射器 --> <mappers> <mapper resource="com/sound/code/mybatis/mapper/roleMapper.xml"/> </mappers> </configuration>
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(inputStream);
public static SqlSessionFactory codeBuildSqlSessionFactory() { // 数据库连接池 PooledDataSource dataSource = new PooledDataSource(); dataSource.setDriver("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"); dataSource.setUsername("root"); dataSource.setPassword("123456"); // 数据库事务方式 TransactionFactory transactionFactory = new JdbcTransactionFactory(); // 运行环境 Environment environment = new Environment("development", transactionFactory, dataSource); // Configuration对象 Configuration configuration = new Configuration(environment); // 注册一个mybatis上下文别名 configuration.getTypeAliasRegistry().registerAlias("role", Role.class); // 加入一个映射器 configuration.addMapper(RoleMapper.class); // 使用configuration对象构建sqlSessionFactory = DefaultSqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); return sqlSessionFactory; }
public interface RoleMapper {
Role getRole(Long id);
int insertRole(Role role);
int deleteRole(Long id);
}
<?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.sound.code.mybatis.mapper.RoleMapper"> <select id="getRole" parameterType="long" resultType="role"> select id, role_name as roleName, note from t_role where id = #{id} </select> <insert id="insertRole" parameterType="role"> insert into t_role(role_name, note) values (#{roleName}, #{note}) </insert> <delete id="deleteRole" parameterType="long"> delete from t_role where id = #{id} </delete> </mapper>
<?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></properties> <!-- 设置 --> <settings></settings> <!-- 类别名 --> <typeAliases> <typeAlias alias="role" type="com.sound.code.mybatis.po.Role"/> </typeAliases> <!-- 类型处理器 --> <typeHandlers></typeHandlers> <!-- 对象工厂 --> <objectFactory type=""></objectFactory> <!-- 插件 --> <plugins> <plugin interceptor=""></plugin> </plugins> <!-- 环境 --> <environments default="development"> <!-- 环境变量 --> <environment id="development"> <!-- 事务管理器 --> <transactionManager type="JDBC"> <property name="autoCommit" value="false"/> </transactionManager> <!-- 数据源 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!-- 数据库厂商标识 --> <databaseIdProvider type=""></databaseIdProvider> <!-- 映射器 --> <mappers> <!-- 加入一个 --> <mapper resource="com/sound/code/mybatis/mapper/roleMapper.xml"/> <!-- 包扫描,多个 --> <!-- <package name="com.sound.code.mybatis.mapper"/> --> </mappers> </configuration>
<!-- 属性 --> <properties> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </properties> <!-- 数据源 --> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource>
#dataSource.properties文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=123456
<!-- 配置文件中引入外部properties文件,mybatis配置文件上下文中就可通过表达式使用 -->
<properties resource="dataSource.properties"></properties>
public static SqlSessionFactory initSqlSessionFactory() { String resource = "mybatis-config.xml"; InputStream inputStream = null; Properties properties = new Properties(); try { inputStream = Resources.getResourceAsStream(resource); Base64.Decoder decoder = Base64.getDecoder(); properties.load(inputStream); // 对数据库密码解密 properties.setProperty("password", new String(decoder.decode(properties.getProperty("username")))); } catch (Exception e) { Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE, null, e); } synchronized (CLASS_LOCK) { if (sqlSessionFactory == null) { // 使用properties中的值 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, properties); } } return sqlSessionFactory; }
在 MyBatis 中 settings 是最复杂的配置,它能深刻影响 MyBatis 底层的运行,但是在大部分情况下使用默认值便可以运行,所以在大部分情况下不需要大量配置它,只需要修改一些常用的规则即可,比如自动映射、驼峰命名映射、级联规则、是否启动缓存、执行器(Executor)类型等
配置项 | 作用 | 配置选项 | 默认值 |
---|---|---|---|
cacheEnabled | 该配置影响所有映射器中配置缓存的全局开关 | true/false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。在特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态 | true/false | false |
aggressiveLazyLoading | 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载 | true/felse | 版本3.4.1 (不包含)之前 true,之后 false |
multipleResultSetsEnabled | 是否允许单一语句返回多结果集(需要兼容驱动) | true/false | true |
useColumnLabel | 使用列标签代替列名。不同的驱动会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果 | true/false | true |
useGeneratedKeys | 允许JDBC 支持自动生成主键,需要驱动兼容。如果设置为 true,则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby) | true/false | false |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射。 PARTIAL 表示只会自动映射,没有定义嵌套结果集和映射结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套) | NONE、PARTIAL、FULL | PARTIAL |
autoMappingUnkno wnColumnBehavior | 指定自动映射当中未知列(或未知属性类型)时的行为。 默认是不处理,只有当日志级别达到 WARN 级别或者以下,才会显示相关日志,如果处理失败会抛出 SqlSessionException 异常 | NONE、WARNING、FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 是普通的执行器;REUSE 会重用预处理语句(prepared statements);BATCH 执行器将重用语句并执行批量更新 | SIMPLE、REUSE、BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数 | 任何正整数 | Not Set (null) |
defaultFetchSize | 设置数据库驱动程序默认返回的条数限制,此参数可以重新设置 | 任何正整数 | Not Set (null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用分页(RowBounds)。如果允许,设置 false | true | false |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则映射,即从经典数据库列名 a_column 到经典 Java 属性名 aColumn 的类似映射 | true | false |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速联复嵌套査询。默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlScssion 的不同调用将不会共享数据 | SESSION/STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER | NULL、VARCHAR、OTHER | OTHER |
lazyLoadTriggerMethods | 指定哪个对象的方法触发一次延迟加载 | — | equals、clone、hashCode、toString |
defaultScriptingLanguage | 指定动态 SQL 生成的默认语言 | — | org.apache.ibatis .script.ing.xmltags .XMLDynamicLanguageDriver |
callSettersOnNulls | 指定当结果集中值为 null 时,是否调用映射对象的 setter(map 对象时为 put)方法,这对于 Map.kcySet() 依赖或 null 值初始化时是有用的。注意,基本类型(int、boolean 等)不能设置成 null | true/false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀 | 任何字符串 | Not set |
proxyFactory | 指定 MyBatis 创建具有延迟加栽能力的对象所用到的代理工具 | CGLIB/JAVASSIST | JAVASSIST (MyBatis 版本为 3.3 及以上的) |
vfsImpl | 指定 VFS 的实现类 | 提供 VFS 类的全限定名,如果存在多个,可以使用逗号分隔 | Not set |
useActualParamName | 允许用方法参数中声明的实际名称引用参数。要使用此功能,项目必须被编译为 Java 8 参数的选择。(从版本 3.4.1 开始可以使用) | true/false | true |
org.apache.ibatis.type.TypeAliasRegistry类的构造方法中定义了所有系统别名,并缓存在了map中
基本数据类型、基本数据包装类型、基本类型数组、基本数据包装类型数组
别名 | 映射类型 | 数组别名 |
---|---|---|
_int | int | _int[] |
int | Integer | int[] |
date | Date | date[] |
decimal | BigDecimal | decimal[] |
bigDecimal | BigDecimal | decimal[] |
object | Object | object[] |
string | String | 无 |
map | Map | 无 |
hashmap | Hashmap | 无 |
list | List | 无 |
arraylist | ArrayList | 无 |
collection | Collection | 无 |
iterator | Iterator | 无 |
ResultSet | ResultSet | 无 |
<!-- 单一自定义别名 -->
<typeAliases>
<typeAlias alias="role" type="com.sound.code.mybatis.po.Role"/>
</typeAliases>
<!-- 包扫描 -->
<typeAliases>
<package name="com.sound.code.mybatis.po"/>
</typeAliases>
public enum Sex { MALE(5, "男"), FEMALE(8, "女"); private Integer code; private String name; Sex(Integer code, String name) { this.code = code; this.name = name; } // 省略get、set方法 public static Sex getSex(int id) { Map<Integer, Sex> map = Arrays.asList(values()).stream().collect(Collectors.toMap(Sex::getCode, Function.identity())); return map.get(id); } } // 自定义枚举类型处理器 public class SexEnumTypeHandler extends BaseTypeHandler<Sex> { // 入库时存入枚举的序列号 @Override public void setNonNullParameter(PreparedStatement ps, int i, Sex parameter, JdbcType jdbcType) throws SQLException { ps.setInt(i, parameter.getCode()); } // 获取枚举 @Override public Sex getNullableResult(ResultSet rs, String columnName) throws SQLException { int id = rs.getInt(columnName); return Sex.getSex(id); } @Override public Sex getNullableResult(ResultSet rs, int columnIndex) throws SQLException { int id = rs.getInt(columnIndex); return Sex.getSex(id); } @Override public Sex getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return null; } }
<!-- 类型处理器 -->
<typeHandlers>
<!-- javaType为枚举类,handler为自定义类型处理器 -->
<typeHandler handler="com.sound.code.mybatis.typeHandler.SexEnumTypeHandler" javaType="com.sound.code.mybatis.contant.Sex"/>
</typeHandlers>
public class Role {
private Long id;
// PO中直接依赖枚举
private Sex sex;
}
<resultMap id="roleMap" type="role"> <id column="id" property="id"/> <result column="sex" property="sex" typeHandler="com.sound.code.mybatis.typeHandler.SexEnumTypeHandler"/> </resultMap> <!-- 根据数据库sex列可直接查询出Sex枚举类到PO --> <select id="getRole" parameterType="long" resultMap="roleMap"> select id, role_name as roleName, note, sex from t_role where id = #{id} </select> <!-- 可将枚举按照自定义规则存入数据库 --> <insert id="insertRole" parameterType="role"> insert into t_role(role_name, note, sex) values (#{roleName}, #{note}, #{sex}) </insert>
<!-- 环境 --> <environments default="development"> <!-- 环境变量 --> <environment id="development"> <!-- 事务管理器 --> <transactionManager type="JDBC"> <property name="autoCommit" value="false"/> </transactionManager> <!-- 数据源 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments>
environments中的属性default,标明在缺省的情况下,我们将启用哪个数据源配置
environment元素是配置一个数据源的开始,属性id是设置这个数据源的标志,以便 MyBatis上下文使用它
transactionManager配置的是数据库事务,其中type属性有3种配置方式
transactionManager中的property元素是配置数据源的各类属性,我们这里配置了 autoCommit= false则是要求数据源事务不自动提交
dataSource标签,是配置数据源连接的信息,type属性是提供我们对数据库连接方式的配置
dataSource标签中的 property元素,就是定义数据库的各类参数(driver, url, username, password)
public static void main(String[] args) { SqlSession sqlSession = null; try { sqlSession = SqlSessionFactoryUtil.openSqlSession(); RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); Role role = new Role(); role.setRoleName("sdf"); role.setNote("fdsa"); role.setSex(Sex.MALE); roleMapper.insertRole(role); roleMapper.deleteRole(1L); // 以上事务同时提交 sqlSession.commit(); } catch (Exception e) { System.out.println(e.getMessage()); sqlSession.rollback(); } finally { if (Objects.nonNull(sqlSession)) { sqlSession.close(); } }
MyBatis内部为我们提供了3种数据源的实现方式,即数据源的属性type取值
UNPOOLED,非连接池,使用 MyBatis提供的 org.apache ibatis datasource unpooledUnpooledData Source实现。
POOLED,连接池,使用 MyBatis提供的 org. apache ibatis datasource pooled. PooledDataSource实现。
JNDI,使用 My Batis提供的 org.apache ibatis datasource jndi. JndiDataSourceFactory来获取数据源
若需要使用自定义数据源,必须去实现 org.apacheibatisdatasource. DataSourceFactory接口
<!-- 文件路径引入 --> <mappers> <mapper resource="com/sound/code/mybatis/mapper/roleMapper.xml"/> </mappers> <!-- mapper接口引入 --> <mappers> <mapper class="com.sound.code.mybatis.mapper.RoleMapper"/> </mappers> <!-- 文件URL引入 --> <mappers> <mapper url="file:///var/mappers/com/sound/code/mybatis/mapper/roleMapper.xml"/> </mappers> <!-- 包扫描引入多个映射器--> <mappers> <package name="com.sound.code.mybatis.mapper"/> </mappers>
元素名称 | 描述 | 备注 |
---|---|---|
selet | 查询语句,最常用、最复杂的元素之一 | 可以自定义参数,返回结果集等 |
insert | 插入语句 | 执行后返回一个整数,代表插入的条数 |
update | 更新语句 | 执行后返回一个整数,代表更新的条数 |
delet | 删除语句 | 执行后返回一个整数,代表删除的条数 |
parameterMap | 定义参数映射关系 | 即将被删除的元素,不建议大家使用 |
sql | 允许定义一部分的 SQL,然后在各个地方引用 | 例如,一张表列名,我们可以一次定义,在多个SQL 语句中使用它 |
reutMap | 用来描述从数据库结果集中来加载对象,它是最复杂、最强大的元素 | 它将提供映射规则 |
cache | 给定命名空间的缓存配置 | |
cache- ref | 其他命名空间缓存配置的引用 |
<!-- keyProperty属性指定哪个是主键字段,useGeneratedKeys属性告诉MyBatis主键是否使用数据库内置策略生成 -->
<insert id="insertRole" parameterType="role" keyProperty="id" useGeneratedKeys="true">
insert into t_role(role_name, note, sex)
values (#{roleName}, #{note}, #{sex})
</insert>
代码中获取新插入数据的id值
Role role = new Role();
role.setRoleName("sdf");
role.setNote("fdsa");
role.setSex(Sex.MALE);
roleMapper.insertRole(role);
sqlSession.commit();
// 可直接获取回填的id值
Long id = role.getId();
<insert id="insertRole" parameterType="role" keyProperty="id" useGeneratedKeys="true">
<!-- keyProperty为主键字段,resultType为主键对应的pojo属性类型,sql为生成规则 -->
<selectKey keyProperty="id" resultType="long" order="BEFORE">
select if(max(id)is null,1,max(id)+ 2)as newId from t_role
</selectKey>
insert into t_role(id,role_name, note, sex)
values (#{id}, #{roleName}, #{note}, #{sex})
</insert>
<!-- 包含以下元素 -->
<resultMap>
<constructor>
<idArg/>
<arg/>
</constructor>
<id/>
<result/>
<association/>
<collection/>
<discriminator>
<case></case>
</discriminator>
</resultMap>
<resultMap>
<constructor>
<!-- 数据库主键字段 -->
<idArg column="id" jdbcType="BIGINT" javaType="long"/>
<!-- 数据库其他字段 -->
<arg column="role_name" jdbcType="VARCHAR" javaType="string"/>
</constructor>
</resultMap>
public class Role { private Long id; private String roleName; private RoleCard roleCard; // 省略set、get方法 } public class RoleCard { private long id; private String code; // 省略set、get方法 } public interface RoleMapper { Role getRole(Long id); } public interface RoleCardMapper { RoleCard getRoleCardByRoleId(long roleId); }
<!-- 定义roleCardMapper的映射关系 --> <select id="getRoleCardByRoleId" parameterType="long" resultType="org.example.mybatis.po.RoleCard"> select id, code, role_id from t_role_card where role_id = #{roleId} </select> <!-- 定义roleMapper的映射关系,将getRole查询的结果id,作为参数传递给getRoleCardByRoleId --> <resultMap id="roleMap" type="role"> <id column="id" property="id"/> <result column="role_name" property="roleName" javaType="string" jdbcType="VARCHAR"/> <!-- property为Role属性映射,column是作为参数的查询结果,select是接收column的sql语句--> <association property="roleCard" column="id" javaType="org.example.mybatis.po.RoleCard" select="org.example.mybatis.mapper.RoleCardMapper.getRoleCardByRoleId"/> </resultMap> <select id="getRole" parameterType="long" resultMap="roleMap"> select id, role_name, note, sex from t_role where id = #{id} </select>
<resultMap id="getRoleAndCardByIdResult" type="role"> <id column="id" property="id"/> <result column="role_name" property="roleName" javaType="string" jdbcType="VARCHAR"/> <result column="note" property="note" jdbcType="VARCHAR"/> <result column="sex" property="sex" typeHandler="org.example.mybatis.typeHandler.SexEnumTypeHandler"/> <!-- 将关联查询的字段直接映射在该实体属性roleCard上 --> <association property="roleCard" javaType="org.example.mybatis.po.RoleCard"> <id property="id" column="cardId"></id> <result property="code" column="code"></result> </association> </resultMap> <select id="getRoleAndCardById" parameterType="long" resultMap="getRoleAndCardByIdResult"> SELECT tr.id, tr.note, tr.role_name, tr.sex, rc.id cardId, rc.`code` FROM t_role tr INNER JOIN t_role_card rc ON tr.id = rc.role_id WHERE tr.id = #{id} </select>
<!-- RoleMapper.xml --> <select id="getRoleByUid" parameterType="long" resultMap="getRoleByUidResultMap"> select id, role_name, note, sex, uid from t_role where uid = #{uid} </select> <!-- UserMapper.xml --> <resultMap id="findUserAndRoleByIdResultMap" type="org.example.mybatis.po.User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="password" column="password"/> <result property="age" column="age"/> <result property="pw" column="pw"/> <result property="driverAge" column="driver_age"/> <!-- 一对多级联查询,ofType表示集合中的元素类型,将id传递给getRoleByUid --> <collection property="roleList" ofType="org.example.mybatis.po.Role" column="id" select="org.example.mybatis.mapper.RoleMapper.getRoleByUid"/> </resultMap> <select id="findUserAndRoleById" parameterType="long" resultMap="findUserAndRoleByIdResultMap"> SELECT u.id, u.username, u.`password`, u.age, u.pw, u.driver_age FROM `user` u WHERE u.id = #{id} </select>
<!--对多根据uid查询用户及其关联的订单信息:级联查询的第二种方法(嵌套结果) --> <resultMap id="findUserAndRoleByUserIdResultMap" type="org.example.mybatis.po.User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="password" column="password"/> <result property="age" column="age"/> <result property="pw" column="pw"/> <result property="driverAge" column="driver_age"/> <!-- 对多级联查询,ofType表示集合中的元素类型 --> <collection property="roleList" ofType="org.example.mybatis.po.Role"> <id property="id" column="roleId"/> <result property="roleName" column="role_name"/> <result property="uid" column="uid"/> <!-- 嵌套结果中还可再嵌套其他查询 --> <association property="roleCard" column="roleId" javaType="org.example.mybatis.po.RoleCard" select="org.example.mybatis.mapper.RoleCardMapper.getRoleCardByRoleId"/> </collection> </resultMap> <select id="findUserAndRoleByUserId" parameterType="long" resultMap="findUserAndRoleByUserIdResultMap"> SELECT u.id, u.username, u.`password`, u.age, u.pw, u.driver_age, r.id roleId, r.role_name, r.uid FROM `user` u LEFT JOIN t_role r ON u.id = r.uid WHERE u.id = #{id} </select>
<resultMap id="findUserBySexResultMap" type="org.example.mybatis.po.User"> <!-- 当findUserByEnable查询结果u.enable为1时使用findUserAndRoleByUserIdResultMap这个ResultMap对结果集映射,反之使用2 --> <discriminator javaType="int" column="enable"> <case value="1" resultMap="findUserAndRoleByUserIdResultMap"></case> <case value="2" resultMap="findUserAndRoleByUserIdResultMap1"></case> </discriminator> </resultMap> <select id="findUserByEnable" parameterType="long" resultMap="findUserBySexResultMap"> SELECT u.id, u.username, u.`password`, u.age, u.pw, u.driver_age, u.enable, r.id roleId, r.role_name, r.uid FROM `user` u LEFT JOIN t_role r ON u.id = r.uid WHERE u.id = #{id} </select>
嵌套查询的级联才会存在N+1问题
// 两次查询只会执行一次SQL
SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(45L);
System.out.println("role = " + role);
Role role1 = roleMapper.getRole(45L);
System.out.println("role1 = " + role1);
// 使用不同的Sqlsession,即使查询相同的sql也还是要执行
SqlSession sqlSession1 = SqlSessionFactoryUtil.openSqlSession();
RoleMapper roleMapper1 = sqlSession1.getMapper(RoleMapper.class);
Role role2 = roleMapper1.getRole(45L);
System.out.println("role2 = " + role2);
为了解决不同的 SqlSession 是相互隔离,需要配置二级缓存,使得缓存在 SqlSessionFactory 层面上能够提供给各个 SqlSession 对象共享。 而 SqlSessionFactory 层面上的二级缓存是不开启的,二级缓存的开启需要进行配置
实现二级缓存的时候,MyBatis 要求返回的 POJO 必须是可序列化的,也就是要求实现 Serializable接口
使用二级缓存,sqlsession调用了commit后才会生效
sqlSession = SqlSessionFactoryUtil.openSqlSession();
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(45L);
System.out.println("role = " + role);
Role role1 = roleMapper.getRole(45L);
System.out.println("role1 = " + role1);
// 开启二级缓存只有执行commit后,非当前sqlsesion执行相同SQL才会使用缓存
sqlSession.commit();
SqlSession sqlSession1 = SqlSessionFactoryUtil.openSqlSession();
RoleMapper roleMapper1 = sqlSession1.getMapper(RoleMapper.class);
Role role2 = roleMapper1.getRole(45L);
System.out.println("role2 = " + role2);
<!-- 在需要缓存数据的mapper.xml中配置cache即可 -->
<mapper namespace="org.example.mybatis.mapper.RoleMapper">
<cache/>
</mapper>
开启后的默认值
缓存策略
<!-- 在需要缓存数据的mapper.xml中配置cache即可 -->
<mapper namespace="org.example.mybatis.mapper.RoleMapper">
<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/>
</mapper>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-redis</artifactId>
<version>1.0.0-beta2</version>
</dependency>
host=192.168.8.29 port=6379 password= timeout=5000 connectionTimeout=5000 soTimeout=5000 database=9 usePool=true #redis pool configuration maxTotal=600 maxIdle=300 minIdle=10 maxWaitMillis=2000 testOnBorrow=false testOnReturn=falseb
<cache type="org.mybatis.caches.redis.RedisCache" eviction="LRU" size="1024"/>
元素 | 作用 | 备注 |
---|---|---|
if | 判断语句 | 单条件分支判断 |
choose(when、otherwise) | 相当于Java中的case when语句 | 多条件分支判断 |
trim(where、set) | 辅助元素 | 用于处理一些SQL拼装问题 |
foreach | 循环语句 | 在in语句等列举条件常用 |
<select id="selectUserByIf" resultType="com.po.MyUser" parameterType="com.po.MyUser">
select * from user where 1=1
<if test="uname!=null and uname!=''">
and uname like concat('%',#{uname},'%')
</if >
<if test="usex !=null and usex !=''">
and usex=#{usex}
</if >
</select>
<select id="selectUserByChoose" resultType="com.po.MyUser" parameterType= "com.po.MyUser">
select * from user 1 = 1
<choose>
<when test="uname!=null and uname!=''">
and uname like concat('%',#{uname},'%')
</when>
<when test="usex!=null and usex!=''">
and usex=#{usex}
</when>
<otherwise>
and uid > 10
</otherwise>
</choose>
</select>
<select id="selectUserByTrim" resultType="com.po.MyUser"parameterType="com.po.MyUser">
select * from user
<trim prefix="where" prefixOverrides = "and | or">
<if test="uname!=null and uname!=''">
and uname like concat('%',#{uname},'%')
</if>
<if test="usex!=null and usex!=''">
and usex=#{usex}
</if>
</trim>
</select>
<!--使用where元素根据条件动态查询用户信息-->
<select id="selectUserByWhere" resultType="com.po.MyUser" parameterType="com.po.MyUser">
select * from user
<where>
<if test="uname != null and uname ! = ''">
and uname like concat('%',#{uname},'%')
</if>
<!-- 这里多了个空格 -->
<if test="usex != null and usex != '' ">
and usex=#{usex}
</if >
</where>
</select>
<!--使用set元素动态修改一个用户-->
<update id="updateUserBySet" parameterType="com.po.MyUser">
update user
<set>
<if test="uname!=null">uname=#{uname}</if>
<if test="usex!=null">usex=#{usex}</if>
</set>
where uid=#{uid}
</update>
collection 该属性是必选的,传递进来List、Set等集合参数名称
item 表示集合中每一个元素进行迭代时的别名
index 指定一个名字,用于表示在迭代过程中每次迭代到的下标位置
open 表示该语句以什么开始
separator 表示在每次进行迭代之间以什么符号作为分隔符
close 表示以什么结束
<!--使用foreach元素查询用户信息-->
<select id="selectUserByForeach" resultType="com.po.MyUser" parameterType=
"List">
select * from user where uid in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
# {item}
</foreach>
</select>
<select id="test" parameterType="java.util.List" resultType="User">
select * from user where id in
<foreach collection="myList" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<select id="dynamicForeach2Test" parameterType="java.util.ArrayList" resultType="User">
select * from user where id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<update id="updateBatch" parameterType="java.util.Map"> update user <trim prefix="set" suffixOverrides=","> <trim prefix="name =case" suffix="end,"> <foreach collection="map" item="i" index="index"> <if test="i.standardFromUuid!=null"> when id=#{i.id} then #{i.standardFromUuid} </if> </foreach> </trim> <trim prefix="standard_to_uuid =case" suffix="end,"> <foreach collection="map" item="i" index="index"> <if test="i.standardToUuid!=null"> when id=#{i.id} then #{i.standardToUuid} </if> </foreach> </trim> </trim> where id in <foreach collection="map" item="i" open="(" separator="," close=")"> #{i.id} </foreach> </update>
List<RoleBean> findRole(@Param("roleName")String roleName,@Param("note") String note);
<!-- bind自定义上下文变量 -->
<select id="findRole" resultType="com.learn.chapter5.mybatis.bean.RoleBean">
<bind name="pattern_roleName" value="'%'+ roleName +'%'"/>
<bind name="pattern_note" value="'%'+ note + '%'"/>
SELECT id,role_name as roleName,create_date as createDate, end_date as endFlag,end_flag as endFlag,note FROM
t_role where role_name like #{pattern_roleName} and note like #{pattern_note}
</select>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。