Mybatis框架
用处:
1.持久层框架,可以避免几乎所有的jdbc和手动设置参数以及获取结果集,2013年迁移至github。
数据持久化:
- 持久化就是将程序的数据在持久层状态和瞬时状态转化过程
- 内存:断电即失
- 数据库(jdbc),io文件持久化
- 生活:冷藏,罐头
为什么要持久化:
- 有一些对象,不能让他丢掉
- 内存很贵
2.简化jdbc操作
补充:修改数据库时区问题
1.找到mysql文件,输入密码进入系统
set global time_zone ='+8:00'
- 设置时区:default-time_zone='+8:00';
- 刷新使其立即生效: flush privileges;
1.创建mybatis流程
1.1配置环境
maven仓库:
-
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency>
配置maven路径path以及maven仓库(自定义仓库maven-rop)
-
连接数据库(注意要修改mysql时区加上&serverTimezone=Asia/Shanghai)
-
配置mybatis数据(到官网mybatis – MyBatis 3 | 入门查找相关信息)
<?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"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
导入数据,包括数据库,mybatis,junit
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
编写mybatis工具类(从xml中构建SqlSessionFactory)
//sql session 工具类
public class Mybatisutils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用mybatis第一步:获取sqlSessionFactory对象
String resource = "mybatis-config.xml";//xml资源加载
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//sqlSession完全包含了SQL命令执行语句
public static SqlSession getSqlSession(){
SqlSession sqlSession=sqlSessionFactory.openSession();//创建sqlsession对象
return sqlSession;
}
}
1.2创建一个模块
1.3编写代码
1.实体类
public class user {
private int id,pwd;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPwd() {
return pwd;
}
public void setPwd(int pwd) {
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "user{" +
"id=" + id +
", pwd=" + pwd +
", name='" + name + '\'' +
'}';
}
}
2.dao接口
public interface Userdao {
List<user>getUserList();
}
3.接口实现类由原来的UserDao/map转变为一个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=绑定一个对应的dao/mapper接口-->
<mapper namespace="com.dam.dao.Userdao">
<!--查询语句-->
<select id="getUserList" resultType="com.dam.dao.user" >
select * from user
</select>
</mapper>
1.4测试
Junit测试:
public class UserdaotestTest {
@Test
public void test(){
//第一步:获得sqlSession对象
SqlSession sqlSession= Mybatisutils.getSqlSession();
//获取接口
Userdao mapper= sqlSession.getMapper(Userdao.class);
List<user> userList= mapper.getUserList();
for (user user : userList) {
System.out.println(user);
}
sqlSession.close();
}
}
注意经典错误:
在pom.xml中写入
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
2.实现增删改查
namespace中的包名要和dao/mapper接口名保持一致
-
编写接口
public interface UserMapper { // 获取所有用户结果集 List<User> getUserList(); // 通过id获取用户 List<User> getUserById(int id); // 添加用户 int add(User user); // 修改用户信息 int update(User user); // 删除用户 int delete(int id); }
-
编写对应的mapper中的sql语句
<mapper namespace="com.dsm.dao.UserMapper"> <select id="getUserList" resultType="com.dsm.pojo.User"> select * from mybatis.user1 </select> <select id="getUserById" resultType="com.dsm.pojo.User" parameterType="int"> select * from user1 where id=#{id} </select> <insert id="add" parameterType="com.dsm.pojo.User" > insert into mybatis.user1(id, name, pwd) VALUES (#{id},#{name},#{pwd}) </insert> <update id="update" parameterType="com.dsm.pojo.User"> update mybatis.user1 set pwd=#{pwd} where id=#{id} </update> <delete id="delete" parameterType="int"> delete from mybatis.user1 where id=#{id} </delete> </mapper>
-
测试(注意增删改查操作需要提交事务!!!)
public class UserDaoTest { @Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.getUserList(); for (User user:userList){ System.out.println(user); } sqlSession.close(); } @Test public void getUserById(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userById = mapper.getUserById(1); System.out.println(userById); sqlSession.close(); } @Test public void add(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int dsm3 = mapper.add(new User(3, "dsm3", "000")); if (dsm3>0){ System.out.println("添加成功"); } sqlSession.commit();//提交事务,否则数据库数据不会有变化 sqlSession.close(); } @Test public void update(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int dsm3 = mapper.update(new User(3, "dsm3", "111")); if (dsm3>0){ System.out.println("修改成功"); } sqlSession.commit(); sqlSession.close(); } @Test public void delete(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int delete = mapper.delete(3); if (delete>0){ System.out.println("删除成功"); } sqlSession.commit(); sqlSession.close(); } }
Map和模糊查询拓展
如果我们的实体类或者数据库中的表,字段很多,我们应当考虑用Map
Map能够做到只添加用户个别信息,如果不用该方法,每次插入需要插入用户所有信息
//使用map添加用户信息
int adduser1(Map<String,Object> map);
<insert id="adduser1" parameterType="map">
insert into mybatis.user1(id, name) VALUES (#{userid},#{username});
@Test
public void adduser1(){
SqlSession sqlSession = Mybatisutils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("userid",4);
map.put("username","dsm4");
mapper.adduser1(map);
sqlSession.commit();
sqlSession.close();
}
模糊查询(like):
注意:模糊查询有两种方式
- 一种直接传入通配符例如List
dsm = mapper.getuserlike("%dsm%");方式 - 另一种直接在sql语句凭借字符串,如select *from mybatis.user1 where name like "%"#{value}"%",该方法可能产生sql注入,不安全
//模糊查询
List<user> getuserlike(String value);
<select id="getuserlike" resultType="com.dsm.pojo.user">
select *from mybatis.user1 where name like #{value};
</select>
@Test
public void getuserlike(){
SqlSession sqlSession = Mybatisutils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<user> dsm = mapper.getuserlike("%dsm%");//注意代码执行的时候,传递通配符%%(或者"%"#{value}"%",但是"%"#{value}"%"的方法可能会有sql注入,不安全)
for (user user : dsm) {
System.out.println(user);
}
sqlSession.close();
}
3.配置解析
3.1.核心配置文件
默认配置文件:mybatis-config.xml 。MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
-
configuration(配置)
properties(属性)--重要 settings(设置)--重要 typeAliases(类型别名)--重要 typeHandlers(类型处理器)--了解 objectFactory(对象工厂)--了解 plugins(插件)--了解 environments(环境配置)--了解 environment(环境变量)--了解 transactionManager(事务管理器)--了解 dataSource(数据源)--了解 databaseIdProvider(数据库厂商标识)--了解 mappers(映射器)--了解
3.2环境变量(environm)
sqlSessionFactory只能选择一种环境
学会使用多套配置环境
<environments default="development">//default="..."默认选项
<environment id="development">//一个environment
<transactionManager type="JDBC"/>//事务管理器(有两种一个常用的默认的是jdbc,另一个不常用的managed)
<dataSource type="POOLED">//数据源,连接数据库,poole池,可回收
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
3.3属性(properties)
properties resource="..."用来引用配置文件
编写一个配置文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
注意在配置下xml文件时,标签都要规定顺序:
<configuration>
<properties resource="db.properties">//引入properties资源
<property name="username" value="root"/>
<property name="pwd" value="123456"/>
</properties>
<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="${pwd}"/>
</dataSource>
</environment>
</environments>
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件的!
3.4类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写
第一种
<typeAliases>
<typeAlias type="com.dsm.pojo.user" alias="User"></typeAlias>
</typeAliases>
<select id="getuserlike" resultType="User">
select *from mybatis.user1 where name like #{value} ;
</select>
第二种
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean
扫描实体类的包,他的默认别名就为这个类的类名,首字母小写
<typeAliases>
<typeAlias type="com.dsm.pojo.user" alias="User"></typeAlias>
<package name="com.dsm.pojo"/>
</typeAliases>
< select id="getuserlike" resultType="user">
select *from mybatis.user1 where name like #{value} ;
</ select>
在实体类比较少的地方使用第一种方式,如果实体类很多,建议使用第二种方式
第一种可以diy,第二种不行,如果非要改,就需要在实体类上增加注解
@Alias("user")
public class User {...}
3.5设置(settings)
(该内容仅了解即可)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 | true | false | False |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
3.6其他配置
- typeHandlers(类型处理器)--了解
- objectFactory(对象工厂)--了解
- plugins(插件)--了解
3.7映射器(mapper)
方式一
<mappers>
<mapper resource="com/dsm/dao/UserMapper.xml"></mapper>
</mappers>
方式二使用class类绑定注册
注意:
- 接口和mapper配置文件必须在同一个包下
- 接口名和mapper配置文件名必须一致
<mappers>
<mapper class="com.dsm.dao.UserMapper"></mapper>
</mappers>
方式三使用扫描包
注意:
- 接口和mapper配置文件必须在同一个包下
- 接口名和mapper配置文件名必须一致
<mappers>
<!--<mapper resource="com/dsm/dao/UserMapper.xml"></mapper>-->
<!-- <mapper class="com.dsm.dao.UserMapper"></mapper>-->
<package name="com.dsm.dao.UserMapper"/>
</mappers>
3.8作用域(Scope)和生命周期
不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder
- 一旦创建了SqlSessionFactoryBuilder,就不再需要它了
- 局部变量
SqlSessionFactory
- 说白了就是可以想象为数据库连接池
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,不要重复创建
- 最简单的就是使用单例模式或者静态单例模式。
SqlSession
-
连接到连接池的一个请求
-
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
-
用完之后需要赶紧关闭,否则资源会被占用
下面的示例就是一个确保 SqlSession 关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) {
// 你的应用逻辑代码
}
在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。
4.解决属性名和字段名不一致的问题(resultMap结果集映射)
解决属性名和字段名不一致问题
id name pwd
id name password
方法一:起别名
select id,name,psw as pwd from mybatis.user1
方法二:结果集映射
<resultMap id="Usermapper" type="user">
<!-- column 数据库中的字段,property实体类中的属性-->
<result column="pwd" property="paw"></result>
</resultMap>
<!--resultType=".."的值需要与resultMap 的id值一致-->
<select id="getuserlike" resultType="Usermapper">
select *from mybatis.user1 where name like #{value} ;
</select>
上述语句只是简单地将所有的列映射到 HashMap
的键上,这由 resultType
属性指定。
-
resultMap
元素是 MyBatis 中最重要最强大的元素。 -
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
8、配置之映射器说明
9、生命周期和作用域
10、ResultMap结果集映射
12、Log4j讲解
13、Limit实现分页
15、使用注解开发
17、注解增删改查
19、复杂查询环境搭建
21、一对多的处理
动态sql的if语句,foreach,常用标签
一级缓存,二级缓存
5.日志工厂
如果一个数据库操作出现错误,日志可以帮助我们排错
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING |
---|---|---|
需要掌握LOG4J, STDOUT_LOGGING(标准日志输出)
注意大小写以及不要有空格
Opening JDBC Connection
Created connection 1883840933.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@704921a5]
> Preparing: select * from mybatis.user1 where id=?;
> Parameters: 1(Integer)
< Columns: id, name, paw
< Row: 1, dsm1, 123
<== Total: 1
user{id=1, name='dsm1', pwd='123'}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@704921a5]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@704921a5]
Returned connection 1883840933 to pool.
LOG4J日志详用
1.导入jar包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.在CLASSPATH下建立log4j.properties。内容如下(数字为行号):
log4j.rootCategory=INFO, 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=D:\\Tomcat ``5.5``\\logs\\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
log4j.logger.com.neusoft=DEBUG
log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR
log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN
log4j.logger.org.displaytag=ERROR
log4j.logger.org.springframework=DEBUG
log4j.logger.com.ibatis.db=WARN
log4j.logger.org.apache.velocity=FATAL
log4j.logger.com.canoo.webtest=WARN
log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.logicalcobwebs=WARN
3.配置log4j为日志的实现
static Logger logger = Logger.getLogger(UserMapper.class);
logger.debug("debug");
logger.info("info");
logger.error("error");
6.分页查询
6.1limit分页
//分页查询
List<user> getUserByLimit(Map<String,Integer> map);
<select id="getUserByLimit" parameterType="map">
select * from my mybatis.user1 limit #{startIndex},#{pageSize};
</select>
@Test
public void getUserBylimit() {
SqlSession sqlSession = Mybatisutils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String,Integer> map= new HashMap<String,Integer>();
map.put("startIndex",0);
map.put("pageSize",2);
List<user> userList = mapper.getUserByLimit(map);
for (user user : userList) {
System.out.println(user);
}
sqlSession.close();
6.2RowBounds分页
1.接口
List<User> getUserByRowBounds();
2.mapper.xml
<select id="getUserByRowBounds" resultMap="UserMap">
select * from mybatis.user1
</select>
3.测试
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
RowBounds rowBounds = new RowBounds(1, 2);
List<User> uiserList = sqlSession.selectList("com.dsm.dao.UserMapper.getUserByRounds", null, rowBounds);
for (User user:uiserList){
System.out.println(user);
}
sqlSession.close();
}
6.3分页插件(pageHelper)
7.使用注解开发
接口,底层主要应用于反射
@Select("select * from mybatis.user1")
List<User> getUsers();
// 方法存在多个参数,必须使用注解@Param(“id")注解
@Select("select * from mybstis.user1 where id=#{id}")
List<User> getUserById(@Param("id") int id);
@Param Parameter N/A 如果你的映射器的方法需要多个参数, 这个注解可以被应用于映射器的方法 参数来给每个参数一个名字。否则,多 参数将会以它们的顺序位置来被命名 (不包括任何 RowBounds 参数) 比如。 #{param1} , #{param2} 等 , 这 是 默 认 的 。 使 用 @Param(“person”),参数应该被命名为 #{person}。
配置文件的mapper需要改变,由于没有xml资源,需要映射类资源
<mappers>
<mapper class="com.dsm.dao.UserMapper"></mapper>
</mappers>
// 查询所有用户
@Test//测试
public void getUsers(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUsers();
for (User user:users){
System.out.println(user);
}
List<User> userById = mapper.getUserById(1);
System.out.println(userById);
sqlSession.close();
}
补充:#{}预编译sql比较安全,${}没有预编译
8.Lombok
1.在idea安装Lombok的插件
2.导入jar包
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
该插件可使用的注解:
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system
Code inspections
Refactoring actions (lombok and delombok)
@Data://经常会用,包含无参构造方法以及get,set,toString,hashcode,equals
@AllArgsConstructor:有参构造
@NoArgsConstructor:无参构造
缺点:
不支持多种参数构造器的重载
虽然省去了手动创建get/set方法的麻烦,但大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度
9.多对一处理
举例:多个学生,对应一个老师
对于学生而言,关联..多个学生关联一个老师(多对一)
对于老师而言,集合,一个老师对很多学生(一对多)
环境搭建
1.导入lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
2.新建实体类teacher,student
3.建立mapper接口
4.建立mapper.xml文件
5.在核心配置文件绑定注册我们的mapper接口或者文件
6.查询测试
两种多对一查询方式
<mapper namespace="com.dsm.dao.StudentMapper">
<!--按结果嵌套处理,联表查询-->
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id as sid,s.name as sname,t.name as tname
from student s,teacher t
where s.tid=t.id;
</select>
<resultMap id="StudentTeacher2" type="com.dsm.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="com.dsm.pojo.Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
<!--
子查询:
1.查询所有的学生信息
2.根据查询出来的学生的tid,寻找对应的老师!子查询
-->
<select id="getStudent" resultMap="TeacherStudent">
select * from student
</select>
<resultMap id="TeacherStudent" type="com.dsm.pojo.Student">
<!-- 复杂的属性,对象:association 集合:collection-->
<association property="teacher" column="tid" javaType="com.dsm.pojo.Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="com.dsm.pojo.Teacher">
select * from teacher where id=#{id}
</select>
</mapper>
10.一对多
<!--一对多-->
<mapper namespace="com.dsm.dao.TeacherMapper">
<!--第一种联表-->
<select id="getTeacher1" resultMap="TeacherStudent">
select s.id as sid,s.name as sname,t.name as tname,t.id as tid
from student s,teacher t where s.tid=t.id and t.id=#{tid}
</select>
<resultMap id="TeacherStudent" type="com.dsm.pojo.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- 对象: association 集合:collection
Javatype=“”指定属性的类型
集合中的泛型信息我们用ofType
-->
<collection property="students" ofType="com.dsm.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
<!--第二中子查询-->
<select id="getTeacher2" resultMap="TeacherStudent1">
select * from teacher where id=#{tid}
</select>
<resultMap id="TeacherStudent1" type="com.dsm.pojo.Teacher">
<collection property="students" javaType="ArrayList" ofType="com.dsm.pojo.Student" select="getTeacherById" column="id"/>
</resultMap>
<select id="getTeacherById" resultType="com.dsm.pojo.Student">
select * from student where tid=#{tid}
</select>
</mapper>
小结
1.关联-association【多对一】
2.集合-collection【一对多】
3.javaType & ofType
- javaType用于指定实体类中的属性的类型
- ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
注意点
- 保证sql的可读性
- 注意一对多和多对一中,属性名和字段名的问题
- 如果问题不好排查,可以使用日志,推荐Log4j
(注意补充:MySql引擎,InnoDB底层原理,索引,索引优化等数据库知识点)
动态sql
根据不同的条件生成不同的sql语句
//插入数据
int addBlog(Blog blog);
<insert id="addBlog" parameterType="Blog">
insert into mybatis.blog (id,name,paw) value (#{id},#{name},#{paw})
</insert>
public class MyTest {
@Test
public void addInitBlog(){
SqlSession sqlSession = Mybatisutils.getSqlSession();
Object mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(5);
blog.setName("dsm5");
blog.setPaw("666");
}
}
if语句
List<Blog>queryBlog(Map<String,Integer> map);
<select id="queryBlog" parameterType="map" resultType="blog">
select * from mybatis.user1 where 1=1
<if test="name!=null">
and name=#{name}
</if>
</select>
public void queryBlogIF(){
SqlSession sqlSession = Mybatisutils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap hashMap = new HashMap();
hashMap.put("name", "dsm7");
List<Blog> blogs= mapper.queryBlog(hashMap);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
同样的
choose(when,otherwise)
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
trim(where,set)
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
foreach(遍历)
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
collection:集合名,item:集合项,index:索引,open:开始,separator:分隔符,close:结束
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,排列组合即可
11.缓存
11.1简介
1.什么是缓存【cache】
- 存在内存中的临时数据
- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高效率,解决了高并发系统的性能问题。
2.为什么使用缓存
- 减少数据库的交互次数,减少系统的开销,提高系统效率
3.什么样的数据使用数据库
- 经常查询且不经常改变的数据
11.2Mybatis的缓存
-
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。缓存极大地提升了查询效率
-
Mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
-
默认情况下只有一级缓存(SqlSession级别的缓存,也称本地缓存)
-
二级缓存需要手动开启和配置,它是基于namespace级别的缓存
-
为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过Cache接口来自定义二级缓存
11.3一级缓存
一级缓存也叫本地缓存:SqlSession
- 与数据库同一次会话期间查询到的数据会放到本地缓存中
- 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查数据库
11.4二级缓存
要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
<cache/>
- 二级缓存也叫全局缓存,一级作用域太低所以诞生出二级缓存
- 基于namespace级别的缓存,一个名称空间对应一个二级缓存
工作机制:
- 一个会话查询一条数据,这数据就会被放在当前会话的一级缓存中
- 如果当前会话关闭了,这个会话对应的一级缓存就没了,但是我们想要的是会话关闭了。一级缓存中的数据保存到二级缓存中
- 新的绘画查询信息就可以从二级缓存中获取内容
- 不同的Mapper查出的数据会放在自己对应的缓存中
在setting里开启全局缓存
<settings>
<setting name="cacheEnabled" value="true"></setting>
</settings>
mapper中开启缓存
<cache/>
<select id=".." ... useCache="true">
....
</select>
也可以自定义缓存
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
只有查询才用得上缓存
11.5缓存原理
11.6自定义缓存(ehcache)
Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。
要在程序中使用要先导包
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
在创建ehcache.xml资源包
<?xml version="1.0" encoding="UTF-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="./tmpdir/Tmp_EhCache"/>
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="cloud_user"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
标签:mapper,缓存,name,框架,mybatis,sqlSession,Mybatis,id
From: https://www.cnblogs.com/tanzhenfei/p/17262882.html