java环境:jdk1.8
eclipse:
mysql
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>cn.companygroupId>
<artifactId>mybatisartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>warpackaging>
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.4version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.19version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
project>
//创建数据库
create database mybatis;
//创建用户表
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
//创建订单表
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下单用户id',
`number` varchar(32) NOT NULL COMMENT '订单号',
`createtime` datetime NOT NULL COMMENT '创建订单时间',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
//创建商品表
CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '商品名称',
`price` float(10,1) NOT NULL COMMENT '商品定价',
`detail` text COMMENT '商品描述',
`pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
`createtime` datetime NOT NULL COMMENT '生产日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
//创建订单详细表
CREATE TABLE `orderdetail` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`orders_id` INT ( 11 ) NOT NULL COMMENT '订单id',
`items_id` INT ( 11 ) NOT NULL COMMENT '商品id',
`items_num` INT ( 11 ) DEFAULT NULL COMMENT '商品购买数量',
PRIMARY KEY ( `id` ),
KEY `FK_orderdetail_1` ( `orders_id` ),
KEY `FK_orderdetail_2` ( `items_id` ),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY ( `orders_id` ) REFERENCES `orders` ( `id` ) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY ( `items_id` ) REFERENCES `items` ( `id` ) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE = INNODB AUTO_INCREMENT = 5 DEFAULT CHARSET = utf8;
INSERT INTO `user` ( `id`, `username`, `birthday`, `sex`, `address` )
VALUES
( 1, '王五', NULL, '2', NULL ),
( 10, '张三', '2014-07-10', '1', '北京市' ),
( 16, '张小明', NULL, '1', '河南郑州' ),
( 22, '陈小明', NULL, '1', '河南郑州' ),
( 24, '张三丰', NULL, '1', '河南郑州' ),
( 25, '陈小明', NULL, '1', '河南郑州' ),
( 26, '王五', NULL, NULL, NULL );
INSERT INTO `items` ( `id`, `name`, `price`, `detail`, `pic`, `createtime` )
VALUES
( 1, '台式机', 3000.0, '该电脑质量非常好!!!!', NULL, '2015-02-03 13:22:53' ),
( 2, '笔记本', 6000.0, '笔记本性能好,质量好!!!!!', NULL, '2015-02-09 13:22:57' ),
( 3, '背包', 200.0, '名牌背包,容量大质量好!!!!', NULL, '2015-02-06 13:23:02' );
INSERT INTO `orders` ( `id`, `user_id`, `number`, `createtime`, `note` )
VALUES
( 3, 1, '1000010', '2015-02-04 13:22:35', NULL ),
( 4, 1, '1000011', '2015-02-03 13:22:41', NULL ),
( 5, 10, '1000012', '2015-02-12 16:13:23', NULL );
INSERT INTO `orderdetail` ( `id`, `orders_id`, `items_id`, `items_num` )
VALUES
( 1, 3, 1, 1 ),
( 2, 3, 2, 3 ),
( 3, 4, 3, 4 ),
( 4, 4, 2, 3 );
pom依赖
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>cn.companygroupId>
<artifactId>mybatisartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>warpackaging>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.18version>
dependency>
dependencies>
project>
package test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author 86182
* @date
* @description: 通过单独的jdbc程序,总结其中的问题
*/
public class TestCase {
public static void main(String[] args) {
// 数据库连接
Connection connection = null;
// 预编译的Statement,使用预编译的Statement提高数据库性能
PreparedStatement preparedStatement = null;
// 结果 集
ResultSet resultset = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8&serverTimezone=Asia/Shanghai",
"root", "root");
// 定义sql语句 ?表示占位符
String sql = "select * from user where username=?";
// 获取预处理statement
preparedStatement = connection.prepareStatement(sql);
// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "王五");
// 向数据库发出sql执行查询,查询出结果集
resultset = preparedStatement.executeQuery();
// 遍历查询结果集
while (resultset.next()) {
System.out.println(resultset.getString("id") + " " + resultset.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if(resultset!=null){
try {
resultset.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
1、数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。
设想:使用数据库连接池管理数据库连接
2、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护
将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。
3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护
将sql语句及占位符号和参数全部配置在xml中
4、从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护
将查询的结果集,自动映射成java对象
mybatis是一个持久层的框架,是apache下的顶级项目。
mybatis托管到goole code下,再后来托管到github
mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,
自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
可以将向 preparedStatement中的输入参数自动进行输入映射,
将查询结果集灵活映射成java对象。(输出映射)
1、mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、>一个是缓存执行器。
5、Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。>mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过>Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对>preparedStatement设置参数。
7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过>Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
mybatis运行环境(jar包):
从https://github.com/mybatis/mybatis-3/releases下载,3.5.4版本
mybatis的jar下载地址
lib下:依赖包
mybatis-3.5.4.jar:核心 包
mybatis-3.5.4.pdf,操作指南
加入mysql的驱动包
mysql的驱动包下载地址
日志的jar包下载地址
log4j的jar下载地址
# Global logging configuration
log4j.rootLogger=DEBUG,stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern==%5p [%t] - %m%n
Po类作为mybatis进行sql映射使用,po类通常与数据库表对应
package cn.itcast.mybatis.po;
import java.util.Date;
public class User {
//属性名和数据库表的字段对应
private int id;
private String username;// 用户姓名
private Date birthday;// 生日
private String sex;// 性别
private String address;// 地址
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String toString() {
return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address="
+ address + "]";
}
}
映射文件命名:
User.xml(原始ibatis命名),mapper代理开发映射文件名称叫XXXMapper.xml,
比如:UserMapper.xml、 ItemsMapper.xml
在映射文件中配置sql语句。
<mapper namespace="cn.itcast.mybatis.po">
<select id="findAll" resultType="cn.itcast.mybatis.po.User">
select * from user
select>
<select id="findUserById" resultType="cn.itcast.mybatis.po.User" parameterType="int">
select * from user where id=#{id}
select>
mapper>
<configuration>
<properties resource="db.properties"/>
<typeAliases>
<package name="cn.itcast.mybatis.po"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="sqlmap/User.xml"/>
mappers>
configuration>
package cn.itcast.mybatis.first;
import java.io.IOException;
import java.io.InputStream;
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 cn.itcast.mybatis.po.User;
/**
*
*@author 86182
*@date 2020年2月27日上午12:11:32
*@description:入门程序
*/
public class MybatisFirst {
//根据id查询用户信息,得到一条记录结果
@Test
public void findUserByIdTes() throws IOException {
//mybatis的配置文件
String resource="SqlMapConfig.xml";
//得到配置文件流
InputStream inputStream=Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession
SqlSession ss=sf.openSession();
//通过SqlSession操作数据库
// 第一个参数:映射文件中statement的id,等于=namespace+"."+statement的id
// 第二个参数:指定和映射文件中所匹配的parameterType类型的参数
// sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象
// selectOne查询出一条记录
User user=ss.selectOne("findUserById",1);
System.out.println(user.getUsername());
ss.commit();
//释放资源
ss.close();
}
}
<mapper namespace="cn.itcast.mybatis.po">
<select id="findAll" resultType="cn.itcast.mybatis.po.User">
select * from user
select>
<select id="findUserById" resultType="cn.itcast.mybatis.po.User" parameterType="int">
select * from user where id=#{id}
select>
<select id="findUserByName" resultType="cn.itcast.mybatis.po.User" parameterType="java.lang.String">
select * from user where username like '%${username}%'
select>
mapper>
修改映射文件User.xml
<mapper namespace="cn.itcast.mybatis.po">
<select id="findUserByName2" resultType="cn.itcast.mybatis.po.User" parameterType="java.lang.String">
select * from user where username like concat('%',#{username},'%')
select>
mapper>
测试程序
@Test
public void findUserByName2Test() throws IOException{
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession ss=sf.openSession();
List<User> user=ss.selectList("findUserByName2", "王五");
for (User u : user) {
System.out.println(u.getId()+"——————"+u.getSex());
}
ss.commit();
ss.close();
}
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类
型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简>单类型值,#{}括号中可以是value或其它名称。
表 示 拼 接 s q l 串 , 通 过 {}表示拼接sql串,通过 表示拼接sql串,通过{}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, 可 以 接 收 简 单 类 型 值 或 p o j o 属 性 值 , 如 果 p a r a m e t e r T y p e 传 输 单 个 简 单 类 型 值 , {}可以接 收简单类型值或pojo属性值,如果parameterType传输单个简单类型值, 可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{}括号中只能是value。
会引起sql注入,所以不建议使用
selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)
selectList可以查询一条或多条记录。
在User.xml中添加如下代码
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
insert into user (id,username,birthday,sex,address) values(null,#{username},#{birthday},#{sex},#{address})
insert>
@Test
public void insertUser() throws IOException {
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession ss=sf.openSession();
User user=new User();
user.setUsername("Alice");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("北京房山区");
ss.insert("insertUser", user);
ss.commit();
ss.close();
}
修改User.xml
在Insert插入语句中增加useGeneratedKeys=true,
keyProperty=“id”
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" useGeneratedKeys="true" keyProperty="id">
insert into user (id,username,birthday,sex,address) values(null,#{username},#{birthday},#{sex},#{address})
insert>
测试程序
@Test
public void insertUser() throws IOException {
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession ss=sf.openSession();
User user=new User();
user.setUsername("Halen");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("北京房山区");
ss.insert("insertUser", user);
//获取新增数据的key(主键)
System.out.println(user.getId());
System.out.println(user);
ss.commit();
ss.close();
}
mysql自增主键,执行insert提交之前自动生成一个自增主键
通过mysql函数获取到刚插入记录的自增主键
LAST_INSERT_ID()
是在insert之后调用LAST_INSERT_ID()函数查询自增主键
通过修改sql映射文件,可以将mysql自增主键返回:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" >
<selectKey order="AFTER" keyProperty="id" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
selectKey>
insert into user (id,username,birthday,sex,address) values(null,#{username},#{birthday},#{sex},#{address})
insert>
User.xml中添加如下代码
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
delete>
测试程序
@Test
public void deleteUserTest() throws IOException {
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession ss=sf.openSession();
ss.delete("deleteUser", 29);
ss.commit();
ss.close();
}
User.xml中添加如下代码
<update id="updateUser" parameterType="cn.itcast.mybatis.po.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
update>
测试程序
@Test
public void updateUserTest() throws IOException {
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession ss=sf.openSession();
User user=new User();
user.setId(31);
user.setBirthday(new Date());
user.setAddress("湖北武汉");
user.setSex("0");
user.setUsername("张俊");
ss.update("updateUser", user);
ss.commit();
ss.close();
}
测试程序也可以如下写
@Test
public void updateUser2Test() throws IOException {
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession ss=sf.openSession();
User user=ss.selectOne("findUserById",31);
user.setBirthday(new Date());
user.setAddress("湖北武汉");
user.setSex("0");
user.setUsername("李四");
ss.update("updateUser", user);
ss.commit();
ss.close();
}
hibernate:是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sql,sql语句自动生成了。
对sql语句进行优化、修改比较困难的
应用场景:
用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。
mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM
框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)
应用场景:
适用与需求变化较多的项目,比如:互联网项目
企业进行技术选型,以低成本 高回报作为技术选型的原则,根据项目组的技术力量进行选择。
通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory
SqlSessionFactoryBuilder当成一个工具类使用即可
不需要使用单例模式管理SqlSessionFactoryBuilder
在需要创建SqlSessionFactoryBuilder时候,只需要new一次SqlSessionFactoryBuilder
通过SqlSessionFactory创建SqlSession,使用单例模式管理SqlSessionFactory
(工厂一旦创建,使用一个实例)
将mybatis和spring整合后,使用单例模式管理SqlSessionFactory
SqlSession是一个面向用户(程序员)的接口
SqlSession提供了很多操作数据库的方法:如selectOne(返回单个对象)、selectList(返回单个或多个对象)、
SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性
SqlSession最佳应用场合在方法体内,定义成局部变量使用
程序员需要写dao接口和dao实现类
需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession
package cn.itcast.mybatis.dao;
import cn.itcast.mybatis.po.User;
/**
*
* @author 86182
* @version 1.0
*/
public interface UserDao {
// 根据id查询用户信息
public User findUserById(int id) throws Exception;
// 添加用户信息
public void insertUser(User user) throws Exception;
// 删除用户信息
public void deleteUser(int id) throws Exception;
}
package cn.itcast.mybatis.dao;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import cn.itcast.mybatis.po.User;
public class UserDaoImpl implements UserDao {
//需要向dao实现类中注入SqlSessionFactory
//通过构造方法注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory=sqlSessionFactory;
}
public User findUserById(int id) throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
User user= sqlSession.selectOne("findUserById",id);
sqlSession.commit();
//释放资源
sqlSession.close();
return user;
}
public void insertUser(User user) throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
//执行插入操作
sqlSession.insert("insertUser",user);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
public void deleteUser(int id) throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
//执行插入操作
sqlSession.delete("deleteUser",id);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
}
package cn.itcast.mybatis.dao;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.mybatis.po.User;
public class UserDaoImplTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
//mybatis配置文件
String resource="SqlMapConfig.xml";
//得到配置文件流
InputStream inputStream=Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis配置文件信息
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
// fail("Not yet implemented");
//创建UserDao
UserDao userDao=new UserDaoImpl(sqlSessionFactory);
//调用UserDao
User user=userDao.findUserById(1);
System.out.println(user);
}
}
1、dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。
2、 调用sqlsession方法时将statement的id硬编码了
3、调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。
程序员还需要编写mapper.xml映射文件
程序员编写mapper接口需要遵循一些开发规范,mybatis可以自己生成mapper接口实现类代理对象
开发规范:
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
mapper>
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
<select id="findUserById" resultType="User" parameterType="int">
select * from user where id=#{id}
select>
<select id="findUserByName" resultType="User" parameterType="java.lang.String">
select * from user where username like concat('%',#{username},'%')
select>
<select id="findAllUsers" resultType="User">
select * from user
select>
<insert id="insertUser" parameterType="User">
insert into user values (null,#{username},#{birthday},#{sex},#{address})
insert>
<update id="updateUser" parameterType="User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
update>
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
delete>
mapper>
在SqlMapConfig.xml中引用UserMapper.xml
修改UserMapper
测试程序
package cn.itcast.mybatis.mapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
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.After;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.mybatis.po.User;
public class UserMapperTest {
SqlSessionFactory sf;
SqlSession ss;
@Before
public void setUp() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sf = new SqlSessionFactoryBuilder().build(inputStream);
ss = sf.openSession();
}
@After
public void after() {
ss.commit();
ss.close();
}
/**
*
* 查询所有的用户信息
*
* @throws Exception
*/
@Test
public void testFindAllUsers() throws Exception {
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper mapper = ss.getMapper(UserMapper.class);
List<User> users = mapper.findAllUsers();
for (User user : users) {
System.out.println(user);
}
}
/**
*
* 根据id查询用户信息
*
* @throws Exception
*/
@Test
public void testFindUserById() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
User user = mapper.findUserById(27);
System.out.println(user);
}
/**
* 根据用户名查询用户列表
*
* @throws Exception
*/
@Test
public void testFindUserByName() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
List<User> users = mapper.findUserByName("明");
for (User user : users) {
System.out.println(user);
}
}
/**
* 添加用户信息
*
* @throws Exception
*/
@Test
public void testInsertUser() throws Exception {
User user = new User();
user.setBirthday(new Date());
user.setAddress("安徽黄山");
user.setSex("1");
user.setUsername("张筱雨");
UserMapper mapper = ss.getMapper(UserMapper.class);
mapper.insertUser(user);
}
/**
* 更新用户信息
* @throws Exception
*/
@Test
public void testUpdateUser() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
List<User> user = mapper.findUserByName("张筱雨");
for (User user2 : user) {
user2.setUsername("张晓雨");
mapper.updateUser(user2);
}
}
/**
* 删除用户信息
* @throws Exception
*/
@Test
public void testDeleteUser() throws Exception{
UserMapper mapper=ss.getMapper(UserMapper.class);
mapper.deleteUser(32);
}
}
总结:
将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值
将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其它xml可以引用该db.properties。
db.properties文件配置如下:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
在SqlMapConfig.xml加载属性文件
MyBatis 将按照下面的顺序来加载属性:
mybatis框架在运行时可以调整一些运行参数
例如:开启二级缓存、开启延迟加载
全局参数将会影响mybatis的运行行为
在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些
别名,在mapper.xml中通过别名定义,方便开发。
mybatis中通过typeHandlers完成jdbc类型和java类型的转换。
通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义.
使用相对于类路径的资源
使用mapper接口类路径
按照上边的规范,将mapper.java和mapper.xml放在一个目录 ,且同名。
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型
完成用户信息的综合查询,需要传入查询条件很复杂(可能包括用户信息、其它信息,比如商品、订单的)
针对上边需求,建议使用自定义的包装类型的pojo。
在包装类型的pojo中将复杂的查询条件包装进去。
用户的扩展类
package cn.itcast.mybatis.po;
/**
*
* @author 86182
* @description:
* 用户的扩展类
*
*/
public class UserCustom extends User{
//可以扩展用户的信息
}
包装类
package cn.itcast.mybatis.po;
/**
*
* @author 86182
*@Description:
*
*包装类型
*/
public class UserQueryVo {
//在这里包装所需要的查询条件
//用户查询条件
private UserCustom userCustom ;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
//可以包装其他的查询条件、订单、商品
}
修改UserMapper.xml,添加如下代码
<select id="findUserList" parameterType="UserQueryVo" resultType="UserCustom">
select * from user where user.sex=#{userCustom.sex} and user.username like CONCAT('%',#{userCustom.username},'%')
select>
package cn.itcast.mybatis.mapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
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.After;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.mybatis.po.User;
import cn.itcast.mybatis.po.UserCustom;
import cn.itcast.mybatis.po.UserQueryVo;
public class UserMapperTest {
SqlSessionFactory sf;
SqlSession ss;
@Before
public void setUp() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sf = new SqlSessionFactoryBuilder().build(inputStream);
ss = sf.openSession();
}
@After
public void after() {
ss.commit();
ss.close();
}
/**
*
* 查询所有的用户信息
*
* @throws Exception
*/
@Test
public void testFindAllUsers() throws Exception {
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper mapper = ss.getMapper(UserMapper.class);
List<User> users = mapper.findAllUsers();
for (User user : users) {
System.out.println(user);
}
}
/**
*
* 根据id查询用户信息
*
* @throws Exception
*/
@Test
public void testFindUserById() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
User user = mapper.findUserById(27);
System.out.println(user);
}
/**
* 根据用户名查询用户列表
*
* @throws Exception
*/
@Test
public void testFindUserByName() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
List<User> users = mapper.findUserByName("明");
for (User user : users) {
System.out.println(user);
}
}
/**
* 添加用户信息
*
* @throws Exception
*/
@Test
public void testInsertUser() throws Exception {
User user = new User();
user.setBirthday(new Date());
user.setAddress("安徽黄山");
user.setSex("1");
user.setUsername("张筱雨");
UserMapper mapper = ss.getMapper(UserMapper.class);
mapper.insertUser(user);
}
/**
* 更新用户信息
* @throws Exception
*/
@Test
public void testUpdateUser() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
List<User> user = mapper.findUserByName("张筱雨");
for (User user2 : user) {
user2.setUsername("张晓雨");
mapper.updateUser(user2);
}
}
/**
* 删除用户信息
* @throws Exception
*/
@Test
public void testDeleteUser() throws Exception{
UserMapper mapper=ss.getMapper(UserMapper.class);
mapper.deleteUser(32);
}
/**
* 用户信息的综合查询
* @throws Exception
*/
@Test
public void testFindUserList() throws Exception {
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper mapper = ss.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo=new UserQueryVo();
UserCustom userCustom=new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("张");
userQueryVo.setUserCustom(userCustom);
//调用mapper的方法
List<UserCustom> users = mapper.findUserList(userQueryVo);
for (UserCustom user : users) {
System.out.println(user);
}
}
}
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
需求:
用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页。
修改UserMapper.xml
<select id="findUserListCount" resultType="int" parameterType="UserQueryVo">
select count(*) from user where username=#{userCustom.username} and password=#{userCustom.password}
select>
UserMapper.java中添加如下代码
// 用户信息综合查询总数
public int findUserListCount(UserQueryVo userQueryVo) throws Exception;
测试程序
package cn.mybatis.mapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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.After;
import org.junit.Before;
import org.junit.Test;
import cn.mybatis.pojo.User;
import cn.mybatis.pojo.UserCustom;
import cn.mybatis.pojo.UserQueryVo;
public class UserMapperTest {
SqlSessionFactory sf;
SqlSession ss;
@Before
public void before() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sf = new SqlSessionFactoryBuilder().build(inputStream);
ss = sf.openSession();
}
@After
public void after() {
ss.commit();
ss.close();
}
/**
* 增加用户
*
* @throws Exception
*/
@Test
public void testInsertUser() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
User user = new User();
user.setUsername("张翰");
user.setPassword("1234");
mapper.insertUser(user);
System.out.println(user.getId());
}
/**
* 删除用户
*
* @throws Exception
*/
@Test
public void testDeleteUser() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
mapper.deleteUser(3);
}
/**
* 修改用户信息
*
* @throws Exception
*/
@Test
public void testUpdateUser() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
User user = mapper.findUserById(1);
user.setUsername("张良");
int count = mapper.updateUser(user);
System.out.println(count);
}
/**
* 查找所有的用户信息
*
* @throws Exception
*/
@Test
public void testFindAllUsers() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
List<User> users = mapper.findAllUsers();
for (User user : users) {
System.out.println(user);
}
}
/**
* 根据id寻找用户信息
*
* @throws Exception
*/
@Test
public void testFindUserById() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
User user = mapper.findUserById(1);
System.out.println(user);
}
/**
* 根据用户名模糊查询,查找相关用户信息
*
* @throws Exception
*/
@Test
public void testFindUserByUserName() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
List<User> users = mapper.findUserByUserName("良");
for (User user : users) {
System.out.println(user);
}
}
/**
* 用户信息综合查询
*
* @throws Exception
*/
@Test
public void testFindUserList() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
userCustom.setPassword("123456");
userCustom.setUsername("张良");
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setUserCustom(userCustom);
List<UserCustom> userCustoms = mapper.findUserList(userQueryVo);
for (UserCustom userCustom2 : userCustoms) {
System.out.println(userCustom2.getId() + "-" + userCustom.getUsername() + "-" + userCustom.getPassword());
}
}
/**
* 用户信息综合查询
*
* @throws Exception
*/
@Test
public void testFindUserListCount() throws Exception {
UserMapper mapper = ss.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
userCustom.setPassword("123456");
userCustom.setUsername("张良");
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setUserCustom(userCustom);
int count = mapper.findUserListCount(userQueryVo);
System.out.println(count);
}
}
1.查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射
2.不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。在mapper.java指定的方法返回值类型不一样:
// 根据id查找用户信息
public User findUserById(int id) throws Exception;
// 根据用户名称查找用户信息
public List<User> findUserByUserName(String username) throws Exception;
生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList (返回集合对象调用 ).
mybatis中使用resultMap完成高级输出结果映射
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
1.定义resultMap
2.使用resultMap作为statement的输出映射类型
在UserMapper.xml中添加如下代码:
<resultMap type="User" id="userResultMap">
<id column="id_" property="id"/>
<result column="username_" property="username"/>
<result column="password_" property="password"/>
resultMap>
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
select id id_,username username_,password password_ from user
select>
总结:
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
动态Sql:
mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装
用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql。
对查询条件进行判断,如果输入参数不为空才进行查询条件拼接
UserMapper.xml中
<select id="findUserListBySql" resultType="UserCustom"
parameterType="UserQueryVo">
select * from user
<where>
<if test="userCustom!=null">
<if test="userCustom.username!=null and userCustom.username!=''">
and username like concat('%',#{userCustom.username},'%')
if>
<if test="userCustom.password!=null and userCustom.password!=''">
and password=#{userCustom.password}
if>
if>
where>
select>
UserMapper.java中添加如下代码:
// 用户信息综合查询
public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;
上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段
在UserMapper.xml中添加如下代码:
<sql id="query_useer_where">
<if test="userCustom!=null">
<if test="userCustom.username!=null and userCustom.username!=''">
and username like concat('%',#{userCustom.username},'%')
if>
<if test="userCustom.password!=null and userCustom.password!=''">
and password=#{userCustom.password}
if>
if>
sql>
在UserMapper.xml中继续添加如下代码:
<select id="findUserListBySql" resultType="UserCustom"
parameterType="UserQueryVo">
select * from user
<where>
<include refid="query_useer_where">include>
where>
select>
修改UserMapper.java,添加如下代码
// 使用sql片段进行用户信息综合查询
public List<UserCustom> findUserListBySql(UserQueryVo userQueryVo) throws Exception;
向sql传递数组或List,mybatis使用foreach解析
在用户查询列表和查询总数的statement中增加多个id输入查询
sql语句如下:
两种方法:
select * from user where id=1 or id=2;
select * from user where id in(1,2);
修改UserMapper.xml
在查询条件中,查询条件定义成一个sql片段,需要修改sql片段
<select id="findUserListBySql" resultType="UserCustom"
parameterType="UserQueryVo">
select * from user
<where>
<include refid="query_useer_where">include>
where>
select>
<sql id="query_useer_where">
<if test="userCustom!=null">
<if test="userCustom.username!=null and userCustom.username!=''">
and username like concat('%',#{userCustom.username},'%')
if>
<if test="userCustom.password!=null and userCustom.password!=''">
and password=#{userCustom.password}
if>
<if test="ids!=null">
<foreach collection="ids" item="user_id" open="AND (" close=")" separator="OR">
id=#{user_id}
foreach>
if>
if>
sql>
<foreach collection="ids" item="user_id" open="AND id in(" close=")" separator=",">
#{user_id}
foreach>