sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。
1.导入包 2.配置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> <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/webdemo?serverTimezone=GMT" /> <property name="username" value="root" /> <property name="password" value="stoneSml@123" /> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml" /> </mappers> </configuration>3.编写需要测试的类
public class Employee { private Integer id; private String lastName; private String email; private String gender; /**省略get和set方法*/ }测试类
class MyBatisTest { @Test void test() throws Exception{ String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSessioin=sqlSessionFactory.openSession(); try { Employee employee=openSessioin.selectOne("com.atguigu.mybatis.EmployeeMapper.selectEmp",1); System.out.println(employee); }finally { openSessioin.close(); } } }编写sql文件
<?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="com.atguigu.mybatis.EmployeeMapper"><!--随便起的名字--> <!--id:标签的唯一标识--> <select id="selectEmp" resultType="com.atguigu.mybatis.bean.Employee"> select id,last_name lastName,email from tb1_employee where id = #{id} </select> </mapper>配置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> <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://localhost:3306/mybaties?serverTimezone=GMT" /> <property name="username" value="root" /> <property name="password" value="stoneSml@123" /> </dataSource> </environment> </environments> <mappers> <mapper resource="EmployeeMapper.xml" /> </mappers> </configuration>测试运行结果如下:
DEBUG 07-01 21:25:56,018 ==> Preparing: select id,last_name lastName,email from tb1_employee where id = ? (BaseJdbcLogger.java:145) DEBUG 07-01 21:25:56,045 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 07-01 21:25:56,069 <== Total: 1 (BaseJdbcLogger.java:145) Employee [id=1, lastName=tom, email=tom@atguigu, gender=null]1.创建接口类
public interface EmployeeMapper { public Employee getEmpById(Integer id); }2.创建与接口相对应的sql查询文件
<?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="com.atguigu.mybatis.dao.EmployeeMapper"><!--指定为接口的全类名--> <!--id:Mapper接口中对应的函数方法名--> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"> select id,last_name lastName,email from tb1_employee where id = #{id} </select> </mapper>3.测试方法
@Test public void test01() throws Exception{ String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSession=sqlSessionFactory.openSession(); EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);//代理类 Employee employee=mapper.getEmpById(1); System.out.println(employee); }SqlSesson代表和数据库的一次会话:用完必须关闭。 SqlSession和connection一样都是非线程安全的。 mapper接口没有实现类,但是mybatis会为接口生成一个代理对象。
1.mybaits可以使用properties来引入外部properties配置文件的内容
<?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="dbconfig.properties" ></properties> <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="EmployeeMapper.xml" /> </mappers> </configuration>dbconfig.properties配置文件中的配置如下:
jdbc.driver:com.mysql.cj.jdbc.Driver jdbc.url:jdbc:mysql://localhost:3306/mybaties?serverTimezone=GMT jdbc.username:root jdbc.password:stoneSml@123配置文件
<typeAliases> <typeAlias type="com.atguigu.mybatis.bean.Employee"/> </typeAliases>默认别名是类名小写:employee,别名不区分大小写,alias指定新的别名 sql文件中进行配置
<?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="com.atguigu.mybatis.dao.EmployeeMapper"><!--指定为接口的全类名--> <!--id:标签的唯一标识--> <select id="getEmpById" resultType="employee"> select * from tb1_employee where id = #{id} </select> </mapper>批量起别名代码按如下方式编写
<typeAliases> <package name="com.atguigu.mybatis.bean"/> </typeAliases>会出现命名冲突,可以采用在类上面添加注解的方式来进行名称指定。 @Alias(“emp”) 全部代码为:
<?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="dbconfig.properties" ></properties> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <typeAliases> <package name="com.atguigu.mybatis.bean"/> </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="EmployeeMapper.xml" /> </mappers> </configuration>最终还是希望大家使用全类名的方式来写sql查询语句。
基本数据类型是在前面加上下划线。 其他类型是首字符小写。
主要作用是将数据库中的类型和java中的类进行映射
plugins 四大对象 Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler (getParameterObject, setParameters) ResultSetHandler (handleResultSets, handleOutputParameters) StatementHandler (prepare, parameterize, batch, update, query)
enviroment:配置一个具体的环境信息,必须有两个标签,id代表当前环境的唯一标识 ----transactionManager:配置事务管理器 --------type:事务管理器的类型,JDBC(JdbcTransactionFactory)和MANAGED(JEE容器的方式实现事务的控制,ManagedTransactionFactory) 自定义事务管理器实现TransactionFactory接口,type指定为全类名 ----dataSource:数据源 --------type:UNPOOLED|POOLED|JNDI 也可以使用自定义的连接池,实现DataSourceFactory接口,type指定为全类名 通过配置environments中default指定的值可以实现测试和运行环境的切换
<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>databaseIdProvider:支持多数据厂商的type=“DB_VENDOR”,VendorDatabaseIdProvider 使用的得到数据库厂商的标识(驱动getDatabaseProductName()),MySQL,Oracle,SQL Server,xxxx 配置信息如下:
<databaseIdProvider type="DB_VENDOR"> <property name="MySQL" value="mysql"/> <property name="Oracle" value="oracle"/> <property name="SQL Server" value="sqlserver"/> </databaseIdProvider>查询数据库的配置如下:
<?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="com.atguigu.mybatis.dao.EmployeeMapper"><!--指定为接口的全类名--> <!--id:标签的唯一标识--> <select id="getEmpById" resultType="employee" databaseId="mysql"> select * from tb1_employee where id = #{id} </select> </mapper>批量注册:
接口内容
public interface EmployeeMapper { public Employee getEmpById(Integer id); public boolean addEmp(Employee employee); public void updateEmp(Employee employee); public void deleteEmpById(Integer id); }sql配置文件内容
<?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="com.atguigu.mybatis.dao.EmployeeMapper"><!--指定为接口的全类名--> <!--id:标签的唯一标识--> <select id="getEmpById" resultType="employee" databaseId="mysql"> select * from tb1_employee where id = #{id} </select> <!-- parameterType参数类型,可以省略 mysql支持自增主键:自增主键的获取,mybatis也是利用statement.getGenreatedKeys(); useGeneratedKeys="true",使用自增主键获取主键值策略 keyProperty:指定对应的主键属性,也就是mybatis获取到主键值以后,将这个主键封装给javaBean的哪个属性 --> <insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id"> insert into tb1_employee(last_name,email,gender) values(#{lastName},#{email},#{gender}) </insert> <update id="updateEmp"> update tb1_employee set last_name=#{lastName},email=#{email},gender=#{gender} where id=#{id} </update> <delete id="deleteEmpById"> delete from tb1_employee where id=#{id} </delete> </mapper>测试代码
@Test public void test02() throws Exception{ String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSession=sqlSessionFactory.openSession(); EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);//代理类 Employee employee=new Employee(1,"jerry","jerry@atguigu.com","1"); //mapper.addEmp(employee); //mapper.updateEmp(employee); mapper.deleteEmpById(2); openSession.commit(); System.out.println(employee); }说明: 1.Mybatis允许增删改直接定义一下类型的返回值 Integer、Long、Boolean、void 2. SqlSession openSession=sqlSessionFactory.openSession();需要设置手动提交 SqlSession openSession=sqlSessionFactory.openSession(true);需要设置自动提交 3.在oracle中使用
1.单个参数传值:mybatis不做特殊处理 #{参数名}:取出参数 2.传递多个参数的时候:mybatis会做特殊处理 多个参数会被封装成一个map key:param1…paramN,或者参数的索引也可以 value:传入的参数值 #{}就是从map中获取指定的key的值 例子: 接口中编写如下代码
public interface EmployeeMapper { public Employee getEmpByIdAndLastName(Integer id,String lastName); }sql配置文件中编写如下代码:
<?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="com.atguigu.mybatis.dao.EmployeeMapper"><!--指定为接口的全类名--> <select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee"> select * from tb1_employee where id = #{param1} and last_name=#{param2} </select> </mapper>还可以做命名参数的处理 把接口类中的代码修改成如下的代码:
public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName); sql修改成如下的代码: <select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee"> select * from tb1_employee where id = #{id} and last_name=#{lastName} </select>如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo #{属性名}:取出传入的pojo的属性值
如果多个参数不是业务模型中的数据,没有对应的pojo,为了方便,我们可以传入map #{key}:取出map中对应的值 接口中的代码如下:
public Employee getEmpByMap(Map<String,Object> map);sql配置文件语句如下:
<select id="getEmpByMap" resultType="com.atguigu.mybatis.bean.Employee"> select * from tb1_employee where id = #{id} and last_name=#{lastName} </select>测试代码如下:
@Test public void test02() throws Exception{ String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSession=sqlSessionFactory.openSession(); EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);//代理类 Map<String,Object> map=new HashMap<String,Object>(); map.put("id",1); map.put("lastName", "Tom"); Employee employee=mapper.getEmpByMap(map); System.out.println(employee); }如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写要给TO(Transfer Object)数据传输对象
Page{ int index; int size; }public Employee getEmp(@Param(“id”)Integer id,String lastName); 取值:id==>#{id/param1} lastName==>#{param2} public Employee getEmp(Integer id,@Param(“e”)Employee emp); 取值:id==>#{param1} lastName==>#{param2.lastName/e.lastName} public Employee getEmpById(List ids); 取值:取出第一个id的值:#{list[0]} 特别注意:如果是Collection(List、Set)类型或者是数组 也会特殊处理。也是把传入的list或这数组封装在map中 key:Collection(collection),如果是List还可以使用key(list) 数组(array)
public Employee getEmpByIdAndLastName(@Param(“id”)Integer id,@Param(“lastName”)String lastName); ParamNameResolver解析参数封装map的: 1.names:{0=id,1=lastName} 获取每个标了param注解的参数的@Param的值,id,lastName 每次解析一个参数给map中保存信息,(key:参数索引,value:name值)。name的值:标注了param注解:注解的值。没有标注:①全局配置:useActualParamName(jdk1.8):name=参数名②name=map.size();相当于当前元素的索引
public ParamNameResolver(Configuration config, Method method) { final Class<?>[] paramTypes = method.getParameterTypes(); final Annotation[][] paramAnnotations = method.getParameterAnnotations(); final SortedMap<Integer, String> map = new TreeMap<Integer, String>(); int paramCount = paramAnnotations.length; // 获取每个标了param注解的参数的@Param的值 for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) { if (isSpecialParameter(paramTypes[paramIndex])) { // skip special parameters continue; } String name = null; for (Annotation annotation : paramAnnotations[paramIndex]) { if (annotation instanceof Param) { hasParamAnnotation = true; name = ((Param) annotation).value(); break; } } if (name == null) { // @Param was not specified. if (config.isUseActualParamName()) { name = getActualParamName(method, paramIndex); } if (name == null) { // use the parameter index as the name ("0", "1", ...) // gcode issue #71 name = String.valueOf(map.size()); } } map.put(paramIndex, name); } names = Collections.unmodifiableSortedMap(map); } public Object getNamedParams(Object[] args) { final int paramCount = names.size(); //1.参数为null直接返回 if (args == null || paramCount == 0) { return null; //2.如果只有一个元素,并且没有Param注解 } else if (!hasParamAnnotation && paramCount == 1) { return args[names.firstKey()]; } else { //多个元素 final Map<String, Object> param = new ParamMap<Object>(); int i = 0; //遍历names集合{id=args[0]:1,lastName=args[1]:Tom} for (Map.Entry<Integer, String> entry : names.entrySet()) { param.put(entry.getValue(), args[entry.getKey()]); // add generic param names (param1, param2, ...) //额外的将每一个参数也保存到mao中,使用新的key:param1...paramN //效果:有Param注解可以#{指定的key},或者#{param1} final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1); // ensure not to overwrite parameter named with @Param if (!names.containsValue(genericParamName)) { param.put(genericParamName, args[entry.getKey()]); } i++; } return param; } }#{}:可以获取map中的值或者pojo对象属性的值 ${}:可以获取map中的值或者pojo对象属性的值
select * from tb1_employee where id = ${id} and last_name=#{lastName}Preparing:select * from tb1_employee where id=2 and last_name=? 区别: #{}:是以预编译的形式将数据设置到sql语句中:PreparedStatement;防止sql注入 KaTeX parse error: Expected 'EOF', got '#' at position 48: …下,我们去参数的值都应该去使用#̲{} 原生的jdbc不支持占…{}进行取值 比如分表:按照年份分表拆分
select * from ${year}_salary where xxx; select * from tb1_employee order by ${f_name} ${order}规定参数的一些规则: javaType、jdbcType、mode(存储过程)、numericScale、resultMap、typeHandler、jdbcTypeName jdbcType通常需要在某种特定的条件写被设置: 在我们数据为null的时候,有些数据库可能不能识别mybaits对null的默认处理,比如Oracle(报错) 可能报错如下: JdbcType OTHER:无效的类型,因为mybatis对所有的null都映射的是原生的Jdbc OTHER,oracle不能正确处理;
<select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee"> <selectKey keyProperty="id" order="BEFORE" resultType="Integer"> select EMPLOYESS_SEQ.nextval from dual </selectKey> insert into employees(EMPLOYEE_ID,LAST_NAME,EMALI) values(#{id},#{lastName},#{email,jdbcType=NULL}) </select>另一种解决办法,在配置文件中进行配置。
<setting> <setting name="jdbcTypeForNull" value="NULL"/> </setting>sql配置文件如下:
<select id="getEmpsByLastNameLike" resultType="com.atguigu.mybatis.bean.Employee"> select * from tb1_employee where last_name like #{lastName} </select> @Test public void test02() throws Exception{ String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSession=sqlSessionFactory.openSession(); EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);//代理类 List<Employee> empsByLastNameLike=mapper.getEmpsByLastNameLike("%jerry%"); System.out.println(empsByLastNameLike.size()); for(Employee employee:empsByLastNameLike) { System.out.println(employee); } }接口中配置的方法:
public Map<String,Object> getEmpByIdReturnMap(Integer id);sql配置如下:
<select id="getEmpByIdReturnMap" resultType="map"> select * from tb1_employee where id=#{id} </select>测试中主要调用方法:
Map<String,Object> map=mapper.getEmpByIdReturnMap(1); System.out.println(map);运行结果如下:
DEBUG 07-02 16:07:55,029 ==> Preparing: select * from tb1_employee where id=? (BaseJdbcLogger.java:145) DEBUG 07-02 16:07:55,029 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 07-02 16:07:55,032 <== Total: 1 (BaseJdbcLogger.java:145) {gender=1, last_name=jerry, id=1, email=jerry@atguigu.com}在接口中申明方法
@MapKey("id") public Map<Integer,Employee> getEmpByLastNameLikeReturnMap(String lastName);sql查询如下
<select id="getEmpByLastNameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee"> select * from tb1_employee where last_name like #{lastName} </select>主要的测试代码如下:
Map<Integer,Employee> map=mapper.getEmpByLastNameLikeReturnMap("%jer%"); System.out.println(map);测试结果如下:
{1=Employee [id=1, lastName=jerry, email=jerry@atguigu.com, gender=1], 3=Employee [id=3, lastName=jerry, email=jerry@atguigu.com, gender=1]}不开启驼峰命名法进行映射 接口代码如下
public interface EmployeeMapperPlus { public Employee getEmpById(Integer id); }对应的sql中的文件如下
<?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="com.atguigu.mybatis.dao.EmployeeMapperPlus"> <!-- 自定义某个javaBean的封装规则 --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmp"> <!-- 指定主键 列的封装规则 id:定义主键会在底层优化规则 column:指定哪一列 property:指定对应的javaBean属性 --> <id column="id" property="id"/> <result column="last_name" property="lastName"></result> <!--其他不指定的列会自动封装,我们只要写resultMap就把全部的映射规则都写上--> <result column="email" property="email"></result> <result column="gender" property="gender"></result> </resultMap> <select id="getEmpById" resultMap="MyEmp"> select * from tb1_employee where id=#{id} </select> </mapper>接口的代码如下
public Employee getEmpAndDept(Integer id);sql查询语句如下
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp"> <id column="id" property="id"></id> <result column="last_name" property="lastName"></result> <result column="gender" property="gender"></result> <!-- <result column="did" property="dept.id"></result> <result column="dept_name" property="dept.departmenName"></result> --> <association property="dept" javaType="com.atguigu.mybatis.bean.Department"> <id column="did" property="id"></id> <result column="dept_name" property="departmenName"></result> </association> </resultMap> <select id="getEmpAndDept" resultMap="MyDifEmp"> SELECT e.*,d.dept_name from tb1_dept d,tb1_employee e where d.id=e.d_id and e.id=1 </select>