Mybatis
ORM映射框架,提供动态sql语句(set标签/sql片段/if标签/foreach遍历),提供API(SQlSession里面功能查询列表,直接获取Mapper接口代理对象),日志输出(log4j)
//1)准备好jar包 (mybatis核心jar包)
<!--mybatis核心依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
//2)准备mybatis核心配置文件(sql-config.xml/mybatis-config.xml)
//配置properties(加载外部配置文件)/配置环境/别名/插件配置/开启二级缓存/配置mapper映射器的包名
//3)准备接口文件和映射文件
//XxxDao/XxxMapper----->XxxDao.xml/XxxMapper.xml
//4)读取核心配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml") ;
//5)创建SqlSessionFactoryBuilder--->
public SqlSessionFactory build(InputStream inputStream)
//6)创建执行对象SqlSession
SqlSession sqlSession = sqlSessionFactory对象.openSession() ;
//7)获取接口对象---jdk动态代理
XxxDao xxDao = sqlSession.getMapper(接口类型.class) ;
//8)调用接口方法
...
注意事项
1)接口文件名和映射文件名称一致
2)建议 接口文件所在包的结构和映射文件的包结构一致
3)接口映射文件XxxDao.xml 里面标签的id值必须和接口的方法名一致
4)映射文件中的namespace名称空间必须指定为"接口的完全限定名称"
OGNL
百度介绍:
对象导航图语言(Object Graph Navigation Language),简称OGNL,是应用于Java中的一个开源的表达式语言(Expression Language),它被集成在Struts2等框架中,作用是对数据进行访问,它拥有类型转换、访问对象方法、操作集合对象等功能。--百度百科
ognl简写表达式:
get()去掉,第一个字母小写
属性参数介绍:
parameterType
接口中方法参数的类型, 类型的完全限定名或别名。
resultType
查询结果resultType返回值类型
namesapce
名称空间指定接口的完全限定名称
selectKey
keyColumn:
表的主键字段名称
keyProperty:
实体类的属性名称
resultType:
返回值自增长主键的值类型:当前实体类的完全限定名称或者别名
order:AFTER:
在执行插入语句之后执行selectkey的语句获取最后一次id的值
#mybatis进行sql优化的时候,尽量使用#{} 占位符号
不要使用${} (字符串拼接)
推荐的写法 #{}
log4j日志
pom.xml中导包
先导包--
<!--log4j日志jar包-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
log4j配置类
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
log4j.logger.dao.EmpDao=TRACE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:/Log4j_local/log4j.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
//需要改动的地方就是:
上面的位置插入1)--日志来源 trace 跟踪之意
1)log4j.logger.dao.EmpDao=TRACE
下面改为: 为日志的存储位置(可变)
2)log4j.appender.LOGFILE.File=D:/Log4j_local/log4j.log
mybatis插入数据时获取自增主键(ID)的值
<selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="emp">
select last_insert_id();
</selectKey>
DruidDataSourceFactory
package sanBao.datasource;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
/**
* @Description
* @Author Ysb0808
* @Date 2023/5/6 16:05
**/
public class DruidDataSourceFactory extends PooledDataSourceFactory {
public DruidDataSourceFactory(){
this.dataSource=new DruidDataSource();/*创建德鲁伊数据源*/
}
}
jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=yisanbao19970808
jdbc.maxActive=10
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">
<!--xx.dtd是xml文件约束-->
<configuration>
<!--属性配置-->
<properties resource="jdbc.properties"></properties>
<!--实体类别名配置-->
<typeAliases>
<!--type指定的当前实体类的完全限定名称
alias:实体的类别名(自己指定,见名知意)
这种方式麻烦(实体类很多,配置很多个typeAlias),可以直接指定实体类的包名
所有的实体类的包名就是默认当前类名(建议小写),不区分大小写
-->
<package name="sanBao.pojo"/>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<!--环境配置-->
<environments default="mysql">
<environment id="mysql">
<!--mybatis事务管理器
连接数据库操作
-->
<transactionManager type="JDBC"/>
<!--pooled:启用自带的 连接池-->
<!--使用自己的连接池-->
<dataSource type="sanBao.datasource.DruidDataSourceFactory">
<!-- <dataSource type="POOLED">-->
<!--配置连接池类中的属性-->
<!--${获取外部资源文件的key对应的内容}-->
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
</dataSource>
</environment>
</environments>
<!--映射器-->
<mappers>
<!-- <mapper resource="mapper/EmpDao.xml"></mapper>-->
<package name="sanBao.mapper"/>
</mappers>
</configuration>
MybatisDemo写在src.test.java.MybatisDemo里
package MybatisDemo;
import com.github.pagehelper.PageHelper;
import sanBao.mapper.EmpDao;
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 sanBao.pojo.Emp;
import sanBao.pojo.QueryDemo;
import sanBao.pojo.VoesDemo;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description
* @Author Ysb0808
* @Date 2023/5/5 15:24
**/
public class MybatisDemo {
private EmpDao empDao;
private SqlSession sqlSession;
@Before
public void init() throws IOException {
/*1)读取resource下的mybatis_config.xml文件*/
InputStream resourceAsStream = Resources.getResourceAsStream("config/mybatis_config.xml");
/*2)创建一个对象SqlSessionFactoryBuilder*/
SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
/*3) 创建SqlSessionFactory*/
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
/*4)创建SqlSession -- 执行对象 底层就是PreparedStatement*/
//SqlSession sqlSession = sqlSessionFactory.openSession();/*自动提交*/
sqlSession = sqlSessionFactory.openSession(false);/*手动提交*/
/*5)获取UserDao接口对象 通过动态代理获取接口对象*/
empDao = sqlSession.getMapper(EmpDao.class);
}
/*获取全部员工*/
@Test
public void testfindAllEmp() throws IOException {
/*加入分页*/
//通过mybatis的分页插件完成分页条件
//PageHelper父类有一个API---
PageHelper.startPage(1,4);
/*一页四条数据*/
List<Emp>emps=empDao.findAllEmp();
if(emps!=null || emps.size()>0){
for(Emp emp:emps){
System.out.println(emp);
}
}
}
/*添加员工*/
@Test
public void testAddEmp(){
Emp emp=new Emp();
emp.setName("假路飞");
emp.setSex("男");
emp.setSalary(6000);
emp.setAddress("东海风车村");
System.out.println("添加前"+emp);
empDao.addEmp(emp);
System.out.println("添加后"+emp);
}
/*删除员工*/
@Test
public void testDelEmp(){
empDao.delEmp(14);
}
/*修改员工*/
@Test
public void testUpdateEmp(){
Emp emp=new Emp();
emp.setId(6);
emp.setName("乔巴");
emp.setSex("公");
emp.setSalary(100);
emp.setAddress("磁鼓岛王国");
empDao.updateEmp(emp);
}
/*模糊查询*/
@Test
public void testfindEmpByName(){
List<Emp> findEmpByName=empDao.findEmpByName("%巴%");
if(findEmpByName!=null){
for(Emp e:findEmpByName){
System.out.println(e);
}
}
}
/*---------------------------------------------------------*/
/*测试QueryDemo单条件查询*/
@Test
public void testfindEmpByQuery(){
QueryDemo qd=new QueryDemo();
Emp ep=new Emp();
ep.setName("路飞");
qd.setEmp(ep);
Emp empByQuery = empDao.findEmpByQuery(qd);
System.out.println(empByQuery);
}
/*---------------------------------------------------------*/
/*测试VoesDemo多条件查询*/
@Test
public void testfindEmpByVoes(){
/*第一种方式*/
// Emp empByVoesDemo = empDao.findEmpByVoesDemo("路飞",6000);
//System.out.println(empByVoesDemo);
/*第二种方式*/
Emp empByVoesDemo = empDao.findEmpByVoesDemo("路飞", 6000);
System.out.println(empByVoesDemo);
/*第三种方式*/
//Map map = new HashMap();
//map.put("name", "路飞");
//map.put("salary", 6000);
//.System.out.println(map);
/*第四种方式*/
//VoesDemo vd=new VoesDemo();
//Emp emp = empDao.findEmpByVoesDemo(vd);
//vd.setName("路飞");
//vd.setSalary(6000);
//Emp e = empDao.findEmpByVoesDemo(vd);
//System.out.println(e);
}
@After
public void commitAndColose(){
sqlSession.commit();
sqlSession.close();
}
}
EmpDao(mybatis的持久层接口)
package sanBao.mapper;
import org.apache.ibatis.annotations.Param;
import sanBao.pojo.Emp;
import sanBao.pojo.QueryDemo;
import sanBao.pojo.VoesDemo;
import java.util.List;
import java.util.Map;
/**
* @Description
* @Author Ysb0808
* @Date 2023/5/5 15:08
**/
public interface EmpDao {
/*查询所有员工*/
List <Emp> findAllEmp();
/*添加员工*/
void addEmp(Emp emp);
/*删除员工*/
void delEmp(Integer id);
/*修改员工*/
void updateEmp(Emp emp);
/*模糊查询*/
List<Emp>findEmpByName(String name);
/*通过包装的QueryDemo实体单条件查询指定Emp*/
Emp findEmpByQuery(QueryDemo queryDemo);
/*通过包装的Demo实体多条件查询指定Emp--第一种方法*/
//Emp findEmpByVoesDemo(String name,int salary);
/*通过包装的Demo实体多条件查询指定Emp--第二种方法*/
//推荐方法
//启用mybatis的@Param注解--指定绑定参数名称,这个参数名称就是等会需要赋值的参数(#{参数名称})
Emp findEmpByVoesDemo(@Param("name")String name,@Param("salary")int salary);
/*通过包装的Demo实体多条件查询指定Emp--第三种方法*/
//Emp findEmpByVoesDemo(Map<String,String> map);
/*通过包装的Demo实体多条件查询指定Emp--第四种方法*/
//Emp findEmpByVoesDemo(VoesDemo voesDemo);
}
EmpDao.xml(mybatis的持久层映射文件)
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="sanBao.mapper.EmpDao">
<!--大量的sql标签
id必须和接口文件中的方法名必须一致
当前接口中的方法有返回值,返回值如果是实体类型或者是List集合
输出映射:resultType必须要指定为当前实体类型的完全限定名称
输入映射 paramterType:如果当前接口中方法形式参数是一个实体类型,写上当前类的完全限定名称
如果形式参数String/int,写成String/int/Integer
mybatis中书写sql语句,也必须使用占位符号 #{实体类的属性名称一致}
-->
<!--获取全部员工信息-->
<select id="findAllEmp" resultType="emp">
select * from emp
</select>
<!--增加员工-->
<insert id="addEmp" parameterType="emp">
<selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="emp">
select last_insert_id();
</selectKey>
insert into emp(name,sex,salary,address)values (#{name},#{sex},#{salary},#{address})
</insert>
<!--删除员工-->
<delete id="delEmp" parameterType="emp">
delete from emp where id=#{id}
</delete>
<!--修改员工-->
<update id="updateEmp">
update emp set name=#{name},sex=#{sex},salary=#{salary},address=#{address} where id=#{id}
</update>
<!--模糊查询-->
<select id="findEmpByName" resultType="emp">
select * from emp where name like #{name}
</select>
<!--|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||-->
<!--通过QueryDemo实体查询指定emp
例子:
获取到QueryDemo对象.getEmp().getName();获取到员工名字
QGNL简写表达式 get()去掉 首字母小写
-->
<select id="findEmpByQuery" parameterType="querydemo" resultType="querydemo">
select * from emp where name=#{emp.name}
</select>
<!--|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||-->
<!--通过VoesDemo实体查询指定emp
例子:
三种方式:
1)按照参数的顺序进行查询 param1,param2....
(推荐) 2)注解方式-#{}里的内容需要和@Param里面的参数名称一致
3)Map集合-#{}里的内容需要和map集合的key一致
-->
<!--方式1-->
<!-- <select id="findEmpByVoesDemo" resultType="sanBao.pojo.Emp">
select * from emp where name=#{param1} and salary=#{param2}
</select>-->
<!--方式2-->
<!--
指定多个条件查询用户的方式2:使用mybatis参数绑定注解方式(推荐)
#{}里面的内容需要和@Param里面的参数名称一致
-->
<select id="findEmpByVoesDemo" resultType="emp">
select * from emp where name=#{name} and salary=#{salary}
</select>
<!--方式3-->
<!-- <select id="findEmpByVoesDemo" resultType="sanBao.pojo.Emp">
select * from emp where name=#{name} and salary=#{salary}
</select>-->
<!--方式4-->
<!--<select id="findEmpByVoesDemo" resultType="sanBao.pojo.Emp" parameterType="sanBao.pojo.Emp">
select * from emp where name=#{name} and salary=#{salary}
</select>-->
</mapper>
四种多条件查询
1:按照参数的顺序进行查询
package sanBao.mapper;
....
Emp findEmpByVoesDemo(String name,int salary);
<select id="findUserByMultConditon" resultType="com.qf.pojo.User">
select * from user where username = #{param1} and address = #{param2}
</select>
@Test
public void testfindEmpByVoes(){
/*第一种方式*/
Emp empByVoesDemo = empDao.findEmpByVoesDemo("路飞",6000);
System.out.println(empByVoesDemo);
}
2:(注解方式—推荐)
package sanBao.mapper;
//推荐方法
//启用mybatis的@Param注解--指定绑定参数名称,这个参数名称就是等会需要赋值的参数(#{参数名称})
Emp findEmpByVoesDemo(@Param("name")String name,@Param("salary")int salary);
<!--方式2-->
<select id="findEmpByVoesDemo" resultType="emp">
select * from emp where name=#{name} and salary=#{salary}
</select>
@Test
public void testfindEmpByVoes(){
/*第二种方式*/
Emp empByVoesDemo = empDao.findEmpByVoesDemo("路飞", 6000);
System.out.println(empByVoesDemo);
}
3:Map集合方法
package sanBao.mapper;
/*通过包装的Demo实体多条件查询指定Emp--第三种方法*/
Emp findEmpByVoesDemo(Map<String,String> map);
<!--方式3-->
<select id="findEmpByVoesDemo" resultType="sanBao.pojo.Emp">
select * from emp where name=#{name} and salary=#{salary}
</select>
@Test
public void testfindEmpByVoes(){
/*第三种方式*/
Map map = new HashMap();
map.put("name", "路飞");
map.put("salary", 6000);
System.out.println(map);
}
4:通过自定义的实体类,将查询的参数封装到这个类中
package sanBao.mapper;
/*通过包装的Demo实体多条件查询指定Emp--第四种方法*/
Emp findEmpByVoesDemo(VoesDemo voesDemo);
<!--方式4-->
<select id="findEmpByVoesDemo" resultType="sanBao.pojo.Emp" parameterType="sanBao.pojo.Emp">
select * from emp where name=#{name} and salary=#{salary}
</select>
@Test
public void testfindEmpByVoes(){
/*第四种方式*/
VoesDemo vd=new VoesDemo();
Emp emp = empDao.findEmpByVoesDemo(vd);
vd.setName("路飞");
vd.setSalary(6000);
Emp e = empDao.findEmpByVoesDemo(vd);
System.out.println(e);
}
单条件查询
导入lombok才可以使用注解省写getxxx set xxx
<!--lombok包 省写setxxx()和getxxx()-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
QueryDemo
package sanBao.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Description
* @Author Ysb0808
* @Date 2023/5/6 17:02
**/
/**
* 包装了另一个实体
* 单条件查询例子
* */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryDemo {
private Emp emp;
}
<!--通过QueryDemo实体查询指定emp
例子:
获取到QueryDemo对象.getEmp().getName();获取到员工名字
QGNL简写表达式 get()去掉 首字母小写
-->
<select id="findEmpByQuery" parameterType="querydemo" resultType="querydemo">
select * from emp where name=#{emp.name}
</select>
package sanBao.mapper;
/*通过包装的QueryDemo实体单条件查询指定Emp*/
Emp findEmpByQuery(QueryDemo queryDemo);
mybatis_config.xml[配置类的简化]
类名上右键Copy/ Paste Special -Copy Reference就是复制全限定名称
数据库属性配置
<!--属性配置-->
<properties resource="jdbc.properties"></properties>
分页插件(mybatis配置类中)
<!--分页配置-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
别名配置
<!--实体类别名配置-->
<typeAliases>
<!--type指定的当前实体类的完全限定名称
alias:实体的类别名(自己指定,见名知意)
这种方式麻烦(实体类很多,配置很多个typeAlias),可以直接指定实体类的包名
所有的实体类的包名就是默认当前类名(建议小写),不区分大小写
-->
<package name="sanBao.pojo"/>
映射器配置
<!--映射器-->
<mappers>
<!-- <mapper resource="mapper/EmpDao.xml"></mapper>-->
<package name="sanBao.mapper"/>
</mappers>