一、JDBC原理(预编译处理好处)
(一)JDBC实现步骤
加载驱动
Class.forName("JDBC驱动类的名称");
创建连接
Connection conn = DriverManager.getConnection(数据连接字符串,数据库用户名,密码);
通过连接创建Statement接口
Statement stmt = conn.createStatement();
//查询
ResultSet rs = stmt.executeQuery("SELECT `id`, `name` FROM `master`");
处理返回的结果
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println(id + " " + name);
}
Statement接口方法
ResultSet executeQuery(String sql): 可以执行SQL查询并获取ResultSet对象
int execute Update(String sql): 可以执行插入、删除、更新操作,返回值是执行该操作所影响的行数
boolean execute(String sql): 可以执行任意SQL语句,若结果为ResultSet对象,则返回true;若其为更新计数或者不存在任何结果,则 返回false;
(二)PreparedStatemen接口
PreparedStatement 接口继承自 Statement 接口, PreparedStatement 比普通 Statement 对象使用起来更加灵活,更有效率
- 使用预编译(提高性能)
- 防止sql注入(相比statement的sql拼接)
(三)相比MyBatis操作数据库的劣势
- 操作繁琐
- 频繁地对数据库进行连接和释放操作,势必会降低数据库的性能
二、mybatis核心对象
(一)概述
MyBatis的核心对象分为三块:
- 核心接口类
SqlSessionFactoryBuilder
SqlSessionFactory
SQLSession - mybatis-config.xml 系统核心配置文件
- mapper.xml SQL映射文件
(二)核心接口类关系
(三) 创建SqlSession代码
public class MyBatisUtil {
private static SqlSessionFactory factory;
static{
String resource = "mybatis-config.xml";
try {
InputStream is = Resources.getResourceAsStream(resource);
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession createSqlSession() {
return factory.openSession(false);
}
public static void closeSqlSession(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.close();
}
}
}
三、mybatis参数核心配置文件
(一)文件中的每个配置大节点
(二)完整setting配置
具体配置说明百度
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
四、mybatis的mapper映射文件(标签)
参照博文:增删改查标签参数说明
五、mybaits四种传参
顺序传参方式
mapper.java文件:
public User selectUser(String name, int deptId);
mapper.xml文件:
<select id="selectUser" resultType="com.wyj.entity.po.User">
select * from user where userName = #{0} and deptId = #{1}
</select>
注解@Param传递参数
mapper.java文件:
public User selectUser(@Param("userName") String name, int @Param("deptId") id);
mapper.xml文件:
<select id="selectUser" resultType="com.wyj.entity.po.User">
select * from user where userName = #{userName} and deptId = #{deptId}
</select>
使用Map集合传递参数
mapper.java文件:
public User selectUser(Map<String, Object> params);
mapper.xml文件:
<select id="selectUser" parameterType="java.util.Map" resultType="com.wyj.entity.po.User">
select * from user where userName = #{userName} and deptId = #{deptId}
</select>
使用JavaBean实体类传递参数
mapper.java文件:
public User selectUser(User user);
mapper.xml文件:
<select id="selectUser" parameterType="com.wyj.entity.po.User" resultType="com.wyj.entity.po.User">
select * from user where userName = #{userName} and deptId = #{deptId}
</select>
六、动态sql
if标签
<if test="name != null and name != ''">
and NAME = #{name}
</if>
foreach标签
foreach 标签主要用于构建 in 条件,可在 sql 中对集合进行迭代。也常用到批量删除、添加等操作中
<!-- in查询所有,不分页 -->
<select id="selectIn" resultMap="BaseResultMap">
select name,hobby from student where id in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
Choose标签
choose 中所有 when的条件都不满则时,则执行 otherwise 中的 sql。类似于 Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
<select id="getStudentListChoose" parameterType="Student" resultMap="BaseResultMap">
SELECT * from STUDENT WHERE 1=1
<where>
<choose>
<when test="Name!=null and student!='' ">
AND name LIKE CONCAT(CONCAT('%', #{student}),'%')
</when>
<when test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</when>
<otherwise>
AND AGE = 15
</otherwise>
</choose>
</where>
</select>
where标签
<select id="getStudentListWhere" parameterType="Object" resultMap="BaseResultMap">
SELECT * from STUDENT
<where>
<if test="name!=null and name!='' ">
NAME LIKE CONCAT(CONCAT('%', #{name}),'%')
</if>
<if test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</if>
</where>
</select>
set标签
可以自动去除逗号
<update id="updateStudent" parameterType="Object">
UPDATE STUDENT SET
<if test="name!=null and name!='' ">
NAME = #{name},
</if>
<if test="hobby!=null and hobby!='' ">
MAJOR = #{major},
</if>
<if test="hobby!=null and hobby!='' ">
HOBBY = #{hobby}
</if>
WHERE ID = #{id};
</update>
sql标签
<!-- 查询字段 -->
<sql id="Base_Column_List">
ID,MAJOR,BIRTHDAY,AGE,NAME,HOBBY
</sql>
<select id="selectAll" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM student
<include refid="Example_Where_Clause" />
</select>
七、MyBatis支持的批量操作
- 通过foreach标签实现
- 通过Excutor接口的Batch实现
(一)foreach实现方式
<update id="updateBatch" parameterType="list" keyProperty="id" useGeneratedKeys="true">
<foreach collection="list" index="index" item="item" open="" separator=";" close="">
update t_acl
<set>
acl_desc = #{item.aclDesc,jdbcType=VARCHAR},
update_time = #{item.updateTime,jdbcType=TIMESTAMP}
</set>
WHERE device_id = #{item.deviceId,jdbcType=VARCHAR} and acl_number = #{item.aclNumber,jdbcType=VARCHAR}
</foreach>
</update>
<insert id="insertBatch" parameterType="list" keyProperty="id" useGeneratedKeys="true">
insert into t_acl (device_id, acl_number, acl_desc, create_time, update_time)
values
<foreach collection="list" separator="," item="item" index="index">
(#{item.deviceId,jdbcType=VARCHAR}, #{item.aclNumber,jdbcType=VARCHAR},
#{item.aclDesc,jdbcType=VARCHAR}, #{item.createTime,jdbcType=TIMESTAMP}, #{item.updateTime,jdbcType=TIMESTAMP})
</foreach>
</insert>
<delete id="deleteBatch">
delete from t_acl where id in
<foreach collection="list" index="index" item="item" separator="," open="(" close=")">
#{item.id}
</foreach>
</delete>
注意批量更新的时候,如果使用了druid数据源,则配置的时候要注意:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="jdbc:mysql://10.3.3.133:6789/test?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="test"/>
<property name="password" value="test"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="1"/>
<property name="minIdle" value="1"/>
<property name="maxActive" value="20"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="60000"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
<property name="poolPreparedStatements" value="true"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
<!-- 配置监控统计拦截的filters -->
<!-- <property name="filters" value="stat,log4j,wall"/> 这种配置不支持批量更新语句-->
<property name="filters" value="stat,log4j"/>
</bean>
(二)Executor.Batch方式
@Test
public void batchTest() {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = getUsers();
long startTimeMillis = System.currentTimeMillis();
for (int i = 0; i < users.size(); i++) {
User user = users.get(i);
mapper.insertUser1(user);
}
sqlSession.flushStatements();
System.out.println("batch方式共执行" + (System.currentTimeMillis() - startTimeMillis) + "ms");
}
mybatis batch模式,需要通过手动设置ExecutorType.BATCH,驱动配置添加 rewriteBatchedStatements=true。相比foreach开发较为麻烦,但性能强大,且批量的sql执行完后才做提交事务