Mybatis 介绍
MyBatis 是支持 普通 SQL 查询 , 存储过程 和 高级映射 的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以 及对结果集的检索封装。MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录.
JDBC- dbutils- MyBatis- Hibernate
使用步骤:
一、加入相关的jar包
mybatis-3.2.2.jar
mysql-connector-java-5.1.47.jar
二、创建相应的实体类bean
public class User { private int id; private String name; private int age; }
三、创建mybatis的配置文件
<?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" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> </configuration>
四、创建mybatis的映射文件
<?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:表示名称空间。现在的目的是区分id的. -->
<mapper namespace="com.zhiyou100.xz.mapper.UserMapper">
<!-- 查询所有 -->
<select id="selectAll" resultType="com.zhiyou100.xz.bean.User">
select * from users
</select>
<!-- 根据id查询用户。id:标识该标签。
parameterType:参数类型。可以写 也可以省略
resultType:返回结果的类型。
#{id}:类似于EL表达式。 解析id的值
-->
<select id="getUser" parameterType="int" resultType="com.zhiyou100.xz.bean.User">
select * from users where id=#{id}
</select>
<!--
parameterType:表示user类的对象。
相当于方法:
public void addUser(User user){
user.getName();
user.getAge();
}
-->
<insert id="addUser" parameterType="com.zhiyou100.xz.bean.User">
insert into users(name,age) values(#{name},#{age})
</insert>
<delete id="deleteUser" parameterType="int">
delete from users where id=#{id}
</delete>
<update id="updateUser" parameterType="com.zhiyou100.xz.bean.User">
update users set name=#{name},age=#{age} where id=#{id}
</update>
</mapper>
五、mybatis的映射文件要引入到配置文件中
<!-- 把映射文件引入到配置文件中 --> <mappers> <mapper resource="com/zhiyou100/xz/mapper/UserMapper.xml"/> </mappers>
六、测试
public class Test { //测试根据id查询用户 public static void main(String[] args) throws Exception { //解析配置文件conf.xml Reader reader=Resources.getResourceAsReader("conf.xml"); //获取SessionFactory对象 SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader); //获取Session对象,表示jdbc中connection,操作数据库的 SqlSession session=sessionFactory.openSession(); //getUser是为了得到select中的sql语句 //映射sql的标识字符串 User user=session.selectOne("com.zhiyou100.xz.mapper.UserMapper.getUser", 1); System.out.println(user); } }
七、优化
1.如果映射文件中的查询条件有多个,则可以使用Map集合作为参数
<!-- 查询年龄在10~30之间的用户 1、查询条件不在实体类中。参数类型封装到map中。#{参数}===map的键 2、封装一个实体类。min max 如果在xml文件中出现了特殊字符?1.使用转义字符<:< 2.CDATA --> <select id="selectByAge" parameterType="map" resultType="com.zhiyou100.xz.bean.User"> <![CDATA[select * from users where age>=#{min} and age<=#{max}]]> </select>
2.将属性文件单独列出db.recourses,需要将属性文件导入Mybatis配置文件中,之后使用${}
<!-- 引入数据源文件 --> <properties resource="db.properties"/> <!-- 为实体类取别名 --> <typeAliases> <!-- <typeAlias type="com.zhiyou100.xz.bean.User" alias="u"/> --> <!-- 以下方法以该包下的所有类的类名作为别名 --> <package name="com.zhiyou100.xz.bean"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <!-- 习惯把数据源的信息放到一个属性文件中,后缀名为.properties --> <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>
3.为实体类起别名,为包下所有类起别名,别名为类名(不建议使用,不方便别人解读代码)
<!-- 为实体类取别名 -->
<typeAliases>
<!-- <typeAlias type="com.zhiyou100.xz.bean.User" alias="u"/> -->
<!-- 以下方法以该包下的所有类的类名作为别名 -->
<package name="com.zhiyou100.xz.bean"/>
</typeAliases>
4.加入日志信息log4j.properties,方便我们查错,步骤如下:
把jar包引入;
引入日志文件:log4j.properties
代码如下:
log4j.properties, log4j.rootLogger=DEBUG, Console #Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n log4j.logger.java.sql.ResultSet=INFO log4j.logger.org.apache=INFO log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
八、使用接口结合xml文件:
1.创建一个接口,该接口要和映射文件匹配。方法名=ID名
public interface UserDao { /** * 根据id查询 * @param id * @return */ public User getUser(int id); }
<?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:表示名称空间。这里的namespace一定要与接口所在的包以及接口的名字一样 --> <mapper namespace="com.zhiyou100.xz.dao.UserDao"> <!-- 这里的id一定要与接口中方法的名字进行对照 --> <select id="getUser" parameterType="int" resultType="com.zhiyou100.xz.bean.User"> select * from users where id=#{id} </select> </mapper>
2.映射文件中,命名空间要与映射文件路径一直,例如:com.zhiyou100.klb.dao.UserDao,如上图
3.测试程序运行状况,在junit下创建TestMybatis
import java.io.Reader; 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.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import com.zhiyou100.xz.bean.User; import com.zhiyou100.xz.dao.UserDao; class TestMybatis { static SqlSession session=null; final String str="com.zhiyou100.xz.mapper.UserMapper"; static UserDao userDao; @BeforeAll static void setUpBeforeClass() throws Exception { //解析配置文件conf.xml Reader reader=Resources.getResourceAsReader("conf.xml"); //获取SessionFactory对象 SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader); //获取Session对象,表示jdbc中connection,操作数据库的 session=sessionFactory.openSession(); //得到接口的实现类 userDao=session.getMapper(UserDao.class);//相当于创建一个Dao对象 } @Test void testSelectByAge() { List<User> list=userDao.selectByAge(10, 30); System.out.println(list); } @Test void testId1() { User user=userDao.getUser(1); System.out.println(user); } @Test void testAdd() { userDao.addUser(new User("孔子",2000)); } @Test void testDelete() { userDao.deleteUser(5); } @Test void testUpdate() { userDao.updateUser(new User(6,"孔子",20)); } @AfterAll static void tearDownAfterClass() throws Exception { session.commit();//提交数据 事物管理:要么都执行,要么都不执行 } }
九、解决数据库中的字段与类中的属性不匹配问题
1.在SQL语句中为字段起别名,别名与类的属性名一致
2.利用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"> <!-- namespace:表示名称空间。这里的namespace一定要与接口所在的包以及接口的名字一样 --> <mapper namespace="com.zhiyou100.xz.dao.ClazzDao"> <!-- resultMap:引用resultMap标签 --> <!-- <select id="selectById" resultMap="clazzMapper"> select * from class c,teacher t where c.teacher_id=t.t_id and c_id=#{cid} </select> --> <!-- resultMap:写属性与字段的对应关系 type:表示哪个实体类与表的对应关系 --> <resultMap type="com.zhiyou100.xz.bean.Clazz" id="clazzMapper"> <!-- id:标签标识表中的主键与实体类的值属性对应关系 --> <id column="c_id" property="cid"/> <result column="c_name" property="cname"/> <result column="teacher_id" property="tid"/> <!-- 该类中引入的一的一方的属性 property:属性名 javaType:该属性的Java类型 --> <!-- 链表查询 <association property="teacher" javaType="com.zhiyou100.xz.bean.Teacher"> <id column="t_id" property="tid"/> <result column="t_name" property="tname"/> </association> --> <association property="teacher" javaType="com.zhiyou100.xz.bean.Teacher"> <id column="t_id" property="tid"/> <result column="t_name" property="tname"/> </association> <!-- ofType:集合中泛型的类型 --> <collection property="students" ofType="com.zhiyou100.xz.bean.Student"> <id property="sid" column="s_id"/> <result property="sname" column="s_name"/> </collection> <!-- column:外键列 select="selectByTeacherId" --> <!-- 嵌套查询 <association property="teacher" javaType="com.zhiyou100.xz.bean.Teacher" column="teacher_id" select="com.zhiyou100.xz.dao.TeacherDao.selectByTeacherId"> </association> --> </resultMap> <!-- 嵌套查询 <select id="selectById" resultMap="clazzMapper"> select * from class where c_id=#{cid} </select> <select id="selectByTeacherId" resultType="com.zhiyou100.xz.bean.Teacher"> select t_id tid,t_name tname from teacher where t_id=#{tid} </select> --> <select id="selectById2" resultMap="clazzMapper"> select * from class c, teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{cid} </select> </mapper>
十、Mybatis中${ }和#{ }的区别
- $: 解析时不会为内容添加”” 它是sql语句的拼接存在sql注入的危害。传入的为表结构时
<!-- $ Preparing:insert into users(name,age) values('吴立琪',18):完成sql拼接。Statement sql注入的缺陷 如果你传入的为列名或表名时可以使用$ # insert into users(name,age) values(?,?):防止sql的注入。PreparedStatement --> <insert id="addUser" parameterType="com.zhiyou100.xz.bean.User" > insert into users(name,age) values(#{name},#{age}) </insert>
- #: 解析时会为内容添加””,它的sql是采用占位符,防止sql注入。
十一、添加对象时如何返回ID
<!-- useGeneratedKeys="true" 表示使用字段生成的key keyProperyty:把生产的key赋值到哪个属性上。 --> <insert id="addUser1" parameterType="com.zhiyou100.xz.bean.User" useGeneratedKeys="true" keyProperty="id"> insert into users(name,age) values(#{name},#{age}) </insert>
@Test void testAdd() { User user=new User("张三",20); session.insert(str+".addUser1", user); int id=user.getId();//通过user对象中的getId()方法获取添加记录后返回自增列的值 System.out.println(id); }