ORM模型简介
ORM:对象关系映射
O代表java中的对象,R代表数据库中的表,映射值Java实体类对象与数据库表的对应关系。
![](https://img.haomeiwen.com/i7560768/93dce05e7b68ad12.png)
MyBatis概述
Mybatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。
- 编码传统的硬编码
- 使用xml配置或者注解
- POJO对象和数据库记录直接映射
- 完善的文档支持 中文api http://www.mybatis.org/mybatis-3/zh/java-api.html
Mybatis使用场景
-
更加关注SQL优化的项目(对生产环境进行sql语句优化)
-
需求频繁更新改动的项目
[图片上传失败...(image-110ecf-1539229088607)] -
案例
-
创建mybatis.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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--使用数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mytest"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--映射配置文件的路径-->
<mappers>
<!--<mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
<mapper resource="mapper/usersMapper.xml"></mapper>
</mappers>
</configuration>
- 创建具体实现的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 namespace="com.alan.entity.Users">
<!--id设置名称 resultType一定是实体类的全名称-->
<select id="userlist" resultType="com.alan.entity.Users">
select * from users
</select>
</mapper>
- 测试类 完成查询测试
import com.alan.entity.Users;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestDemo {
/**
* 通过junit进行单元测试
*/
@Test
public void testDemo1() throws IOException {
//初始化mybatis配置环境
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//打开和数据库之间的会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//进行数据库操作 对应usersMapper.xml中配置的select中的id名称
List<Users> usersList = sqlSession.selectList("userlist");
for(Users users:usersList){
System.out.println(users);
}
//关闭会话
sqlSession.close();
}
}
![](https://img.haomeiwen.com/i7560768/7698e8f0617d9344.png)
![](https://img.haomeiwen.com/i7560768/b587a576d1fa36bf.png)
- https://v3.bootcss.com bootstrap中文文档
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配置,用户加载外部的properties配置文件
resource配置具体的properties外部文件
${driver}用这种方式进行赋值
-->
<properties resource="db.properties" ></properties>
<!--
environments 主要用于数据源的配置
可以配置多个数据源:例如测试,验证、生成等环境。
default中配置的是当前选中的数据源
-->
<environments default="development">
<!--
environment 用户配置一个具体的独立的数据源
id属性用于给当前数据源定义一个名称,方便我们的项目指定
-->
<environment id="development">
<!--
transactionManager用于配置事务管理,默认情况下使用的是JDBC事务管理
-->
<transactionManager type="JDBC"/>
<!--
dataSource具体数据源的链接信息:type属性用于指定是否使用连接池,POOLED代表使用连接池
-->
<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>
<environment id="product">
<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>
<environment id="test">
<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>
<!--mapper主要用户配置外部的映射配置文件-->
<mappers>
<!--主要配置引入一个具体的配置文件,通过resource进行路径方式引入-->
<mapper resource="mapper/usersMapper.xml"/>
</mappers>
</configuration>
-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">
<!--
mapper用于定义一个映射配置文件的根结点
namespace属性用来配置命名空间,主要进行session级别的缓存管理
命名空间默认情况下,使用我们当前操作的实体类的全路径
-->
<mapper namespace="com.alan.entity.Users">
<select id="findUsers" resultType="com.alan.entity.Users">
select * from users
<if test="id != null">
where id = #{id}
</if>
</select>
<!--使用SQL动态语句实现-->
<!--<select id="findById" resultType="com.alan.entity.Users">-->
<!--select * from users where id = #{id}-->
<!--</select>-->
</mapper>
resultMap配置
<?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属性用来配置命名空间,主要进行session级别的缓存管理
命名空间默认情况下,使用我们当前操作的实体类的全路径
-->
<mapper namespace="com.alan.entity.Users">
<!--<select id="findUsers" resultType="com.alan.entity.Users">-->
<select id="findUsers" resultMap="forUsers">
select * from users
<if test="id != null">
where id = #{id}
</if>
</select>
<!--自定义映射集合 主要包含对于一些自定义的操作配置,如不一致的属性和字段-->
<resultMap id="forUsers" type="com.alan.entity.Users">
<!--column数据库中的字段对应property实体类中的属性-->
<result column="username" property="name"></result>
</resultMap>
<!--使用SQL动态语句实现-->
<!--<select id="findById" resultType="com.alan.entity.Users">-->
<!--select * from users where id = #{id}-->
<!--</select>-->
</mapper>
log4j在mybatis中的使用
log.info 实现的效果和system.out.println()是一样的,但是开发的时候还是用日志,因为System.out.println输出的内容不能保存到文件中,只能在控制台上显示。
- 在resources目录下配置log4j
#采用DEBUG模式,并增加日志源A1 配置为INFO DEBUG级别日志就不会输出了。
log4j.rootLogger=INFO, A1
# 在控制台进行输出
log4j.appender.A1=org.apache.log4j.ConsoleAppender
#使用固定的格式
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
#格式的具体设置
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
-
自动在控制台打印日志信息
图片.png
-
在类中具体使用方法
package com.alan.servlet;
import com.alan.dao.UsersDAO;
import com.alan.entity.Users;
import org.apache.log4j.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/detail")
public class UsersFindByIdServlet extends HttpServlet {
/**
* 创建对应的日志记录对象
* 通过不同级别进行日志的记录【DEBUG\WARN\INFO\LOG】
*/
private Logger log = Logger.getLogger(UsersFindByIdServlet.class);
private UsersDAO usersDAO = new UsersDAO();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = request.getParameter("id");
log.info("获取到查询参数id:"+id);
Users user = usersDAO.findById(Integer.parseInt(id));
request.setAttribute("user",user);
log.info("查询数据完成,查询到的数据:"+user);
request.getRequestDispatcher("detail.jsp").forward(request,response);
}
}
-
控制台数据输出
图片.png
SQL片段动态语句,当sql语句太长的时候通过这种方式配置
<sql id="user_fields">
username,userpass,nickname,age,gender,email,phone,createTime,updateTime,lastLogin,userStatus,remark
</sql>
<!--keyProperty配置是自动生成主键放入表中的id字段中-->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
-- insert into users(username,userpass,nickname,age,gender,email,phone,createTime,updateTime,lastLogin,userStatus,remark)
insert into users(<include refid="user_fields"></include>)
values (#{name},#{userpass},#{nickname},#{age},#{gender},#{email},#{phone},#{createTime},#{updateTime},#{lastLogin},#{userStatus},#{remark})
</insert>
set动态语句配置
<update id="updateUser">
update users
<set>
<if test="name != null">username = #{name},</if>
<if test="userpass != null">userpass = #{userpass},</if>
<if test="nickname != null">nickname = #{nickname},</if>
<if test="age != null">age = #{age},</if>
<if test="gender != null">gender = #{gender},</if>
<if test="email != null">email = #{email},</if>
<if test="phone != null">phone = #{phone},</if>
<if test="createTime != null">createTime = #{createTime},</if>
<if test="updateTime != null">updateTime = #{updateTime},</if>
<if test="lastLogin != null">lastLogin = #{lastLogin},</if>
<if test="userStatus != null">userStatus = #{userStatus},</if>
<if test="remark != null">remark = #{remark},</if>
</set>
where id = #{id}
</update>
蛋糕商城项目
包括三个模块common、site、management
- common模块包括
1、mybatis配置
2、公共类
3、Maven依赖
4、filter配置(解决乱码问题)
配置pom.xml 添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>MybatisCakeProj</artifactId>
<groupId>com.alan</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>MybatisCakeProj-common</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
![](https://img.haomeiwen.com/i7560768/35ff0c332c4ee32d.png)
通过注解方式配置
-cakeMapper
package com.alan.cake.mapper;
import com.alan.cake.entity.Cake;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* 蛋糕mapper (相当于DAO了)
*/
public interface CakeMapper {
//通过results解决数据库字段名称与实体类属性名称不一致的问题。其中id = true 这行代表是主键
// @Result 前面是数据库字段,后面为实体类属性名称
/**
* 分页查询蛋糕
* @param skip 跳过对记录数,也就是从哪条开始查询
* @param size 每页条数
* @return 蛋糕List集合
*/
@Select("select * from cake order by create_time desc limit #{skip},#{size}")
@Results({
@Result(id = true, column = "id" , property = "id"),
@Result(column = "category_id" , property = "categoryId"),
@Result(column = "name" , property = "name"),
@Result(column = "level" , property = "level"),
@Result(column = "price" , property = "price"),
@Result(column = "create_time" , property = "createTime"),
@Result(column = "update_time" , property = "updateTime"),
})
List<Cake> getCakes(@Param("skip") Integer skip, @Param("size") Integer size);
/**
* 根据分类ID查询蛋糕
* @param categoryId 分类ID
* @param skip 页码
* @param size 每页条数
* @return 蛋糕List集合
*/
@Select("select * from cake where category_id = #{categoryId} order by create_time desc limit #{skip}, #{size}")
@Results({
@Result(id = true, column = "id" , property = "id"),
@Result(column = "category_id" , property = "categoryId"),
@Result(column = "name" , property = "name"),
@Result(column = "level" , property = "level"),
@Result(column = "price" , property = "price"),
@Result(column = "create_time" , property = "createTime"),
@Result(column = "update_time" , property = "updateTime"),
})
//多个参数时,需要对参数加上注解
List<Cake> getCakesByCategoryId(@Param("categoryId") Long categoryId , @Param("skip") Integer skip , @Param("size") Integer size);
/**
* 根据分类ID查询总条数
* @param categoryId 分类ID
* @return 总共的条数
*/
@Select("select count(*) from cake where category_id = #{categoryId}")
int countCakesByCategoryId( Long categoryId);
/**
* 添加蛋糕信息
* @param cake 蛋糕实体类
*/
@Insert("insert into cake(category_id,name,level,price,small_img,create_time,update_time)" +
"value (#{cake.categoryId} ,#{cake.name},#{cake.level},#{cake.price},#{cake.smallImg},#{cake.createTime},#{cake.updateTime})")
void addCake(@Param("cake") Cake cake);
/**
* 返回蛋糕图片
* @param id 蛋糕id
* @return
*/
@Select("select small_img smallImg from cake where id = #{id} for update")
Cake getImg(Long id);
}
- CategoryMapper
package com.alan.cake.mapper;
import com.alan.cake.entity.Category;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 分类mapper
*/
public interface CategoryMapper {
//这里面的注解配置对应mybatis XML的配置
//数据库中的字段名称为create_time update_time,而实例类中为createTime updateTime,这里面查询通过别名方式
@Select("select id ,name, create_time createTime , update_time updateTime from category")
List<Category> getCategories();
/**
* 根据ID删除具体分类
* @param id 要删除的分类ID
*/
@Delete("delete from category where id = #{id}")
void deleteById(Long id);
/**
* 增加分类
* @param category 分类实体类
*/
@Insert("insert into category(name,create_time,update_time) values(#{name},#{createTime},#{updateTime})")
void addCategory(Category category);
}
- CakeService
package com.alan.cake.service;
import com.alan.cake.common.MyBatisUtils;
import com.alan.cake.entity.Cake;
import com.alan.cake.mapper.CakeMapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.session.SqlSession;
import java.util.Date;
import java.util.List;
public class CakeService {
/**
* 根据分类ID查询蛋糕
* @param categoryId 分类ID
* @param page 页码
* @param size 每页条数
* @return 蛋糕List集合
*/
public List<Cake> getCakesByCategoryId( Long categoryId , Integer page , Integer size){
SqlSession sqlSession = MyBatisUtils.oppenSqlSession();
try {
CakeMapper cakeMapper = sqlSession.getMapper(CakeMapper.class);
return cakeMapper.getCakesByCategoryId(categoryId,(page-1)*size,size);
} finally {
sqlSession.close();
}
}
/**
* 添加蛋糕信息
* @param cake 蛋糕实体类
*/
public void addCake(Cake cake){
Date now = new Date();
cake.setCreateTime(now);
cake.setUpdateTime(now);
SqlSession sqlSession = MyBatisUtils.oppenSqlSession();
try {
CakeMapper mapper = sqlSession.getMapper(CakeMapper.class);
mapper.addCake(cake);
//注意:这里需要commit
sqlSession.commit();
} finally {
sqlSession.close();
}
}
/**
* 根据分类ID查询总条数
* @param categoryId 分类ID
* @return 总共的条数
*/
public int countCakesByCategoryId( Long categoryId){
SqlSession sqlSession = MyBatisUtils.oppenSqlSession();
try {
CakeMapper mapper = sqlSession.getMapper(CakeMapper.class);
return mapper.countCakesByCategoryId(categoryId);
} finally {
sqlSession.close();
}
}
/**
* 返回蛋糕图片
* @param id 蛋糕id
* @return
*/
public Cake getImg(Long id){
SqlSession sqlSession = MyBatisUtils.oppenSqlSession();
try {
CakeMapper mapper = sqlSession.getMapper(CakeMapper.class);
return mapper.getImg(id);
} finally {
sqlSession.close();
}
}
}
- CategoryService
package com.alan.cake.service;
import com.alan.cake.common.MyBatisUtils;
import com.alan.cake.entity.Category;
import com.alan.cake.mapper.CategoryMapper;
import org.apache.ibatis.session.SqlSession;
import java.util.Date;
import java.util.List;
public class CategoryService {
/**
* 返回所有分类信息
* @return
*/
public List<Category> getCategories(){
SqlSession sqlSession = MyBatisUtils.oppenSqlSession();
try {
//CakeMapper.class获取类CakeMapper的Class类的对象。然后通过sqlSesson的getMapper方法获取到CakeMapper的对象。这个是MyBatis中通过SqlSession获取mapper对象的方式
CategoryMapper mapper = sqlSession.getMapper(CategoryMapper.class);
return mapper.getCategories();
} finally {
sqlSession.close();
}
}
/**
* 增加分类
* @param category 分类实体类
*/
public void addCategory(Category category){
Date now = new Date();
category.setCreateTime(now);
category.setUpdateTime(now);
SqlSession sqlSession = MyBatisUtils.oppenSqlSession();
try {
CategoryMapper mapper = sqlSession.getMapper(CategoryMapper.class);
mapper.addCategory(category);
sqlSession.commit();
} finally {
sqlSession.close();
}
}
}
- MyBatisUtils.java
package com.alan.cake.common;
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.IOException;
import java.io.InputStream;
/**
* MyBatis工具类
*/
public class MyBatisUtils {
private static final String resource = "config.xml";
private static SqlSessionFactory sqlSessionFactory;
static {
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession oppenSqlSession(){
return sqlSessionFactory.openSession();
}
}
网友评论