【Java18】Mybatis:jdbc解耦,动态代理,日志
文章目錄
- 1.介紹:Mybatis是對數據庫操作,創建maven管理的java工程就可以
- 2.第一個程序:三個.xml文件
- 2.1 pom.xml
- 2.2 log4j.properties
- 2.3 mybatis-config.xml
- 2.4 XxxMapper.xml
- 2.5 jdbc
- 3.dao層的CRUD操作:以前userdao都是用jdbc template實現,現在換成Mybatis,需要一個sqlsession對象
- 3.1 dao:UserDao.java,UserDaoImpl.java
- 3.2 mybatis-config.xml
- 3.3 UserDaoMapper.xml
- 3.4 domain:User.java
- 3.5 test:UserDaoTest.java
- 4.動態代理Dao實現:userDao對象改為userMapper對象
- 4.1 mapper:UserMapper.java
- 4.2 mybatis-config.xml
- 4.3 UserMapper.xml
- 4.4 test:UserMapperTest.java
- 5.動態代理底層原理:接口名和方法名
1.介紹:Mybatis是對數據庫操作,創建maven管理的java工程就可以
Mybatis就是對以前的dao層的封裝,替換jdbc template,但jdbc性能高于Mybatis。ioc就是工廠模式,aop就是動態代理,在spring中我們只需配置就行。springMVC類似Baseservlet(對servlet做了優化,一個類處理多個請求),將參數獲取和返回值給出變得更簡單。
如下第一點:改驅動就是改代碼了,改代碼意味著所有類重新編譯,整個web工程war包重新打包,項目重新發布。
public class JDBCTest {
public static void main(String[] args) throws Exception {
如下是Mybatis組成:MybatisConfig.xml(配置文件,1個):放的是數據源里參數(驅動,地址,用戶名密碼)。Mapper.xml(映射文件,有多少張表有多少個):配置sql語句(sql里參數在java中寫的)以及sql語句返回結果集封裝和映射。
如上解決了jdbc程序缺點小結中的1和2,如下解決3:SqlSession和jdbc template一樣(連接對象獲取,preparestatement對象創建,參數設置,結果集封裝都不用管),SqlSession底層對jdbc操作封裝分為Executor和Mapped Statement兩個部分。
2.第一個程序:三個.xml文件
2.1 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"><modelVersion>4.0.0</modelVersion><groupId>com.itheima</groupId><artifactId>mybatis01</artifactId><version>1.0-SNAPSHOT</version><build><plugins><!-- java編譯插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.2</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build><dependencies><!-- mysql驅動包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version></dependency><!-- mybatis的核心包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version></dependency><!-- log4j日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.6.4</version></dependency><!-- 單元測試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency></dependencies> </project>2.2 log4j.properties
### direct log messages to stdout 輸出到控制臺### log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target=System.outlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %t-[%p] %m%n### direct messages to file mylog.log 輸出到文件### log4j.appender.file=org.apache.log4j.FileAppenderlog4j.appender.file.File=f:/mylog.loglog4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %t-[%p] %m%n### set log levels - for more verbose logging change 'info' to 'debug' ### log4j.rootLogger=debug, stdout,file2.3 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!--xml聲明--> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--xml約束--> <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><mappers><mapper resource="UserMapper.xml"/> <!--有一個配一個--></mappers> </configuration>2.4 XxxMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--mapper標簽: 配置各類聲明namespace:名稱空間(類似java中包名),由于映射文件可能有多個,為了防止crud語句的唯一標識被重復,需要設置空間名稱。--> <mapper namespace="UserMapper"><!--select:查詢的statement(聲明),用來編寫查詢語句id:語句的唯一標識resultType:配置返回的結果集類型parameterType:傳遞的參數類型,可省略--><select id="queryUserById" resultType="com.itheima.domain.User"><!--上行java中才能寫單個User,字符串中不行,必須全類名-->select * from tb_user where id = #{id}</select> </mapper>2.5 jdbc
package com.itheima.jdbc; import com.itheima.domain.User; 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.InputStream;public class MyBatisTest {public static void main(String[] args) throws Exception {//1.獲取mybatis核心配置文件的io流對象,ibatis(mybatis)包下的ResourcesInputStream is = Resources.getResourceAsStream("mybatis-config.xml"); //2.解析配置文件,得到sqlSessionFactory工廠對象SqlSessionFactory sqlSessionFacoty = new SqlSessionFactoryBuilder().build(is); //3.通過工廠創建sqlSession的。SqlSession sqlSession = sqlSessionFacoty.openSession(); //4.通過sqlSession執行sql即可。 第一個參數sql 通過namespace.statementIdUser user = sqlSession.selectOne("UserMapper.queryUserById",1); //第二個參數是sql需要的參數System.out.println(user); //打印出com.itheima.domain.User@29..//重寫User.java中tostring方法打印如下} }如下如果insert,不去手動提交,這樣不會插入數據庫,因為autocommit false關閉了自動提交。
如下通過dom4j解析myb…xml中url等參數放到Configuration對象(數據庫相關)的對應屬性中,同理mapper.xml也是。讀取一個myb…xml就行,利用for循環解析。SqlSession只能是接口,是實現類的話,數據庫不同不能統一管理(基于接口創建對象,一般用工廠模式創建)。SqlSessionFactoryBuilder用來解析myb…xml并傳給后面Configuration對象。
3.dao層的CRUD操作:以前userdao都是用jdbc template實現,現在換成Mybatis,需要一個sqlsession對象
3.1 dao:UserDao.java,UserDaoImpl.java
package com.itheima.dao; import com.itheima.domain.User;public interface UserDao {public void addUser(User user);public void update(User user);public User findUserById(int id);public void deleteById(int id); } package com.itheima.dao.impl; import com.itheima.dao.UserDao; import com.itheima.domain.User; import org.apache.ibatis.session.SqlSession;public class UserDaoImpl implements UserDao {private SqlSession sqlSession; //sqlSession現在是空值,以前直接=new jdbctemplate... //現在不是new一下能搞定的,要1.獲取資源,2.解析配置,3.創建工廠對象,4.sqlSession。如下通過構造傳入。public void setSqlSession(SqlSession sqlSession) { //傳遞賦值,構造和set方法都可以this.sqlSession = sqlSession;}@Overridepublic void addUser(User user) {sqlSession.update("UserDaoMapper.addUser",user); //mybatis會自動將user映射成sql需要的參數}@Overridepublic void update(User user) {sqlSession.update("UserDaoMapper.update",user);}@Overridepublic void deleteById(int id) {sqlSession.update("UserDaoMapper.deleteById",id);}@Overridepublic User findUserById(int id) {User user = sqlSession.selectOne("UserDaoMapper.findUserById", id); //返回user對象return user;} }3.2 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//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><mappers><mapper resource="UserMapper.xml"/><mapper resource="UserDaoMapper.xml"></mapper></mappers> </configuration>3.3 UserDaoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="UserDaoMapper"><select id="findUserById" resultType="com.itheima.domain.User">select * from tb_user where id = #{id}</select><insert id="addUser"> <!-- user對象的屬性-->insert into tb_user(user_name,password,name) values(#{userName},#{password},#{name})</insert><delete id="deleteById">delete from tb_user where id=#{id}</delete><update id="update">update tb_user set age=#{age},sex=#{sex} where id = #{id}</update> </mapper>3.4 domain:User.java
package com.itheima.domain; import java.util.Date;public class User {private Long id; private String userName; // 用戶名 private String password; // 密碼 private String name; // 姓名 private Integer age; // 年齡 private Integer sex; // 性別,1男性,2女性 private Date birthday; // 出生日期 private Date created; // 創建時間 private Date updated; // 更新時間public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Integer getSex() {return sex;}public void setSex(Integer sex) {this.sex = sex;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public Date getCreated() {return created;}public void setCreated(Date created) {this.created = created;}public Date getUpdated() {return updated;}public void setUpdated(Date updated) {this.updated = updated;}@Overridepublic String toString() {return "User{" +"id=" + id +", userName='" + userName + '\'' +", password='" + password + '\'' +", name='" + name + '\'' +", age=" + age +", sex=" + sex +", birthday=" + birthday +", created=" + created +", updated=" + updated +'}';} }3.5 test:UserDaoTest.java
如上選中按ctrl+shift+t產生如下:
4.動態代理Dao實現:userDao對象改為userMapper對象
發現每個dao層sqlSession.insert等每個方法底層都是update實現都是一樣的,只是參數不一樣,所以可以把方法都寫一樣。只有接口,如只有UserDao接口情況下,mybatis幫我們創造實現類UserDaoImpl即動態代理即調用mybatis方法創建的接口類型對象。
如下2,3對應上面2,3。
如下dao文件夾名稱換成mapper文件夾。
4.1 mapper:UserMapper.java
package com.itheima.mapper; import com.itheima.domain.User;public interface UserMapper {public User findUserById(int id);public void deleteById(int id); }4.2 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//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><mappers><mapper resource="UserMapper.xml"/></mappers> </configuration>4.3 UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.mapper.UserMapper"><select id="findUserById" resultType="com.itheima.domain.User">select * from tb_user where id = #{id}</select> </mapper>4.4 test:UserMapperTest.java
所以只需要一個UserMapper接口(不用實現類)就行。
5.動態代理底層原理:接口名和方法名
package com.itheima.proxy; import com.itheima.mapper.UserMapper; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class MapperProxy { //工具類 public static UserMapper getProxyMapper(){ //提供一個方法,創建接口對象的動態代理對象的/*參數1:類加載器,任意一個類加載器即可。參數2: 被代理對象UserMapper實現的接口。參數3:處理器*/ClassLoader classLoader = UserMapper.class.getClassLoader();Class[] classes = new Class[1]; //只有一個UserMapper接口就可以classes[0]=UserMapper.class;UserMapper proxyUserMapper = (UserMapper) Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {/*** @param proxy 代理對象本身,沒用。* @param method 將要執行的方法* @param args 方法需要的參數*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); //獲取將要執行的方法的名字String nameSpace = UserMapper.class.getName(); //mybatis框架規范:1.namespace必須是接口的全限定名。String statementId= methodName; //2.statement的id就是接口的方法名。 String sqlId = nameSpace+"."+statementId; System.out.println("將要執行的sql語句的唯一標識是:"+sqlId);// sqlSession.update(sqlId,args);return null;}});return proxyUserMapper;}public static void main(String[] args) {UserMapper userMapper = getProxyMapper();userMapper.findUserById(1); //運行的是invoke方法// userMapper.deleteById(1); } }如上打印出如下,就是UserMapper.xml中namespace.方法名。
如下所以mybatis要設計一套規范,讓調用者遵循規范寫。
如下日志:
總結
以上是生活随笔為你收集整理的【Java18】Mybatis:jdbc解耦,动态代理,日志的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java13】cookiesessio
- 下一篇: 【Java23】maven加强,分布式R