文章目录
Mybatis
日志介绍
日志级别
OFF<FATAL<ERROR<WARN<INFO<DEBUG<ALL
右边的级别包含左边的全部日志
日志配置
log4j.rootCategory=DEBUG, stdout , R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=F://mybatis.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
ORM介绍
Orm框架:完成数据库表与Javabean对象关系映射的框架就叫orm框架
JDBC:过程太麻烦,orm框架对原始jdbc过程进行封装
常见orm框架
- Mybatis:用得多
- Hibernate:用得少,学习成本高 40-50% 老的管理项目,趋于淘汰
- Springjdbc:(用得少)
Mybatis入门
原名ibatis
mybatis将java代码和sql语句解耦合,将sql语句嵌入到xml配置文件中
1.引入jar包
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
2.实体类
package cn.cdqf.entity;
import java.io.Serializable;
public class User implements Serializable {
private String uname;
private int uid;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", uid=" + uid +
'}';
}
}
3.dao层
public interface UserDao2 {
List<User> queryAll();
User queryByName(@Param("uname") String uname);
User queryByName2(@Param("user") User uname);
void insert(@Param("user") User user);
void insert2(@Param("user") User user);
//根据名称模糊查询 根据年龄范围查询
List<User> queryByNameAndAge(@Param("uname") String uname,@Param("age") int age);
}
package cn.cdqf.dao.impl;
import cn.cdqf.dao.UserDao;
import cn.cdqf.entity.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
public class UserDaoImpl implements UserDao {
public List<User> queryAll() {
//构造者模式 build :构建工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//把配置文件转成输入流
InputStream resourceAsStream = UserDaoImpl.class.getResourceAsStream("/mybatis-config.xml");
//UserDaoImpl.class.getClassLoader().getResourceAsStream()
//所有的构造者模式,有个方法build方法
//工厂模式:造类 创建对象
SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
//拿数据库连接对象 connection mybatis改名为SqlSession
SqlSession sqlSession = build.openSession();
List<User> objects = sqlSession.selectList("cn.cdqf.dao.UserDao.queryAll");
//关闭资源
sqlSession.close();
return objects;
}
}
4.主配置文件
<?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>
</configuration>
<?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="jdbc.properties"></properties>
<typeAliases>
<!--简写 实体类-->
<package name="cn.cdqf.entity"></package>
</typeAliases>
<!--编码环境:Development、Test、Product-->
<!--
prod:生产环境,真实上线 运维
test:测试环境 测试部门
dev:开发环境 开发
-->
<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配置文件-->
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
5.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">
<!--
namespace:来区分当前项目中唯一的一个mapper.xml,一般用接口全路径来标识
-->
<mapper namespace="cn.cdqf.dao.UserDao">
</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">
<!--
namespace:来区分当前项目中唯一的一个mapper.xml,一般用接口全路径来标识
-->
<mapper namespace="cn.cdqf.dao.UserDao">
<!--
id:对应接口中的方法名 id是唯一标识 不会重复
resultType:指定当前查询的返回值,返回值只需要指定集合里面的内容,mybatis会根据sql返回条数自动判断是集合还是单个对象
select:执行体 statement
-->
<select id="queryAll" resultType="cn.cdqf.entity.User">
select * from user_a
</select>
<!--
parameterType:指定参数类型
-->
<select id="queryByName" resultType="User" parameterType="string">
<!--#{名字要跟接口方法中@param注解中指定名字相同}
......where uname=? preparedStatemenet:会把传递字符串参数来的参数加""
预编译平台,防止sql注入
select * from user_a where uname="张三"
"'张三' or 1=1"参数
delete from user_a where uname='张三' or 1=1
delete from user_a where uname="'张三' or 1=1" 预编译平台
-->
select * from user_a where uname=#{uname}
</select>
<select id="queryByName2" resultType="user" parameterType="user">
<!--
$会直接取 传过来对象参数的属性
-->
select * from user_a where uname='${uname}'
</select>
<insert id="insert" parameterType="user">
insert into user_a(uid,uname) values(#{uid},#{uname})
</insert>
<!--
插入的时候获得主键id
1.在insert标签 指定下面三个属性
useGeneratedKeys="true"
keyColumn="uid":指定数据库字段
keyProperty="uid":java对象的字段
2.在insert内部加入如下代码
<selectKey keyProperty="uid" keyColumn="uid" resultType="int">
select last_insert_id();
</selectKey>
-->
<insert id="insert2" parameterType="user">
insert into user_a(uname) values(#{uname})
</insert>
</mapper>
$和#的区别(重点)
取参数
- #采用预编译方式,会将传入的字符串用双引号引起,防止sqk注入
- 直 接 将 值 取 出 , 不 能 防 止 s q l 注 入 , 而 且 直接将值取出,不能防止sql注入,而且 直接将值取出,不能防止sql注入,而且只能接受对象参数
但若涉及到为sql传参以外的sql,如果需要java传递,就必须用**$**取
自定义工具类
package cn.cdqf.util;
import cn.cdqf.dao.impl.UserDaoImpl;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
public enum MyBatisUtil {
INSTANCE;//就是当前类的对象 并且是单例
private static final SqlSessionFactory sqlSessionFactory;
static{
//构造者模式 build :构建工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//把配置文件转成输入流
InputStream resourceAsStream = UserDaoImpl.class.getResourceAsStream("/mybatis-config.xml");
//UserDaoImpl.class.getClassLoader().getResourceAsStream()
//所有的构造者模式,有个方法build方法
//工厂模式:造类 创建对象
sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
}
//获取连接
public SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
//关闭连接
public void close(SqlSession sqlSession){
if(sqlSession!=null)
sqlSession.close();
}
//提交事务
public void commit(SqlSession sqlSession){
if(sqlSession!=null)
sqlSession.commit();//重要,否则更新类型的sql无法同步到数据库
close(sqlSession);
}
//回滚事务
public void rollback(SqlSession sqlSession){
if(sqlSession!=null)
sqlSession.rollback();
close(sqlSession);
}
}
主键返回
<!--
插入的时候获得主键id
-->
1.在insert标签 指定下面三个属性
useGeneratedKeys="true"
keyColumn="uid":指定数据库字段
keyProperty="uid":java对象的字段
2.在insert内部加入如下代码
<selectKey keyProperty="uid" keyColumn="uid" resultType="int">
select last_insert_id();
</selectKey>
动态代理实现
必须满足的条件
- 通过公共接口调用
- mapper.xml中的namespace必须是接口的全限定名
- mapper.xml中的id必须和接口中的方法名一致
安装Free Mybatis plugin插件
多参数 转义<![CDATA[]]> 模糊查询
多个不同类型的参数,parameterType就不写
<select id="queryByNameAndAge" resultType="cn.cdqf.entity.User">
<![CDATA[
select * from user_a where uname like concat("%",#{uname},"%")
and age < #{age}
]]>
</select>
动态Sql
1.if
<!--判断名字不为null 且不为""-->
<if test="uname!=null and uname!=''">
where uname like concat("%",#{uname},"%")
</if>
<if test="age!=null and age>0">
and age>#{age}
</if>
2.where
自动去掉第一个and
<select id="selectUserByIdAndName" resultType="com.edu.entity.User">
select * from users
<where>
<if test="name!=null and name !=''">
and username like concat("%",#{name},"%")
</if>
<if test="id != 0">
and id > #{id}
</if>
</where>
</select>
3.set
自动去掉最后一个","
<update id="update">
<if test="map != null">
update users
<set>
<foreach collection="map" index="key" item="value">
${key} = #{value},
</foreach>
</set>
where id = #{id}
</if>
</update>
4.trim
<update id="update">
<if test="map != null">
update users
<!--prefix:前缀 suffixOverrides:覆盖最后的标记-->
<trim prefix="set" suffixOverrides=",">
<foreach collection="map" index="key" item="value">
${key} = #{value},
</foreach>
</trim>
where id = #{id}
</if>
</update>
5.choose when otherwise
互斥
<select id="selectUserByIdAndName" resultType="com.edu.entity.User">
<bind name="selectStr" value="'%'+name+'%'"/>
select * from users
<trim prefix="where" prefixOverrides="and">
<choose>
<when test="name!=null and name !=''">
username like #{selectStr}
</when>
<otherwise>
and id > #{id}
</otherwise>
</choose>
</trim>
</select>
6.bind(如上)
7.sql include
</select>
<sql id="useSql">
users
</sql>
<select id="selectUserById" resultMap="UserMap" parameterType="int">
select * from
<include refid="useSql"></include>
where id = #{id}
</select>
8.foreach 数组 集合
<update id="update">
<if test="map != null">
update users
<trim prefix="set" suffixOverrides=",">
<!--collection:接口中@Param定义的参数名
若未定义,array:数组,maps:Map
-->
<foreach collection="map" index="key" item="value">
${key} = #{value},
</foreach>
</trim>
where id = #{id}
</if>
</update>
resultMap
<!--
反射设置值,根据数据库列名 来获得属性名
1.改别名(跟属性名相同)
cdqf_tid tid,cdqf_tname tname
2.通过resultMap映射
-->
<resultMap id="baseMap" type="Teacher">
<!--
type="Teacher":属性类型
column:查询出来的列名
property:类中属性名
-->
<id column="cdqf_tid" property="tid"></id>
<result column="cdqf_tname" property="tname"></result>
</resultMap>
<sql id="baseSql">
cdqf_tid,cdqf_tname
</sql>
<select id="queryAll" resultMap="baseMap">
select
<include refid="baseSql"></include>
from cdqf_teacher
</select>
一对一
-
连表查询
<resultMap id="baseMap" type="Student"> <id column="cdqf_sid" property="sid"></id> <result column="cdqf_sname" property="sname"></result> <!-- 映射一对一关系 property:属性名 javaType:当前属性的类型 --> <association property="teacher" javaType="Teacher"> <id column="cdqf_tid" property="tid"></id> <result column="cdqf_tname" property="tname"></result> </association> </resultMap> <select id="queryAll" resultMap="baseMap"> SELECT cdqf_sid,cdqf_sname,cdqf_tname,cdqf_tid FROM cdqf_student s JOIN cdqf_teacher t ON s.`tid`=t.`cdqf_tid` </select>
-
接口调用
<resultMap id="UserMap" type="user"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="password" column="password"/> <result property="tel" column="tel"/> <result property="createTime" column="createTime"/> <!--columu属性将参数传到调用的接口方法中执行查询--> <association property="power" column="power" javaType="Permission" select="com.edu.dao.PowerDao.queryPowerById" > </association> </resultMap> <select id="selectAll" resultMap="UserMap"> select * from users </select>
一对多
-
连表查询
<resultMap id="baseMap" type="Teacher"> <!-- type="Teacher":属性类型 column:查询出来的列名 property:类中属性名 --> <id column="cdqf_tid" property="tid"></id> <result column="cdqf_tname" property="tname"></result> <!--ofType:集合元素得类型 --> <collection property="studentList" ofType="Student"> <id column="cdqf_sid" property="sid"></id> <result column="cdqf_sname" property="sname"></result> </collection> </resultMap> <sql id="baseSql"> cdqf_tid,cdqf_tname </sql> <select id="queryAll" resultMap="baseMap"> SELECT cdqf_tid,cdqf_tname,cdqf_sid,cdqf_sname FROM cdqf_teacher t JOIN cdqf_student s ON t.`cdqf_tid`=s.`tid` </select>
-
接口调用
<resultMap id="Power" type="Permission"> <id property="id" column="id"/> <result property="right" column="right_value"/> <!--columu属性将参数传到调用的接口方法中执行查询--> <collection property="users" column="id" ofType="User" select="com.edu.dao.UserDao.selectUserById"> </collection> </resultMap> <select id="queryAllPower" resultMap="Power"> select * from permission </select>
延迟加载
<settings>
<setting name ="aggressiveLazyLoading" value="false"/>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
一二级缓存
<setting name="localCacheScope" value="SESSION"/>
<setting name="cacheEnabled" value="true"/>
<cache/>